วิธีเปรียบเทียบประเภทของวัตถุใน Python


163

โดยทั่วไปฉันต้องการทำสิ่งนี้:

obj = 'str'
type ( obj ) == string

ฉันเหนื่อย:

type ( obj ) == type ( string )

และมันไม่ทำงาน

แล้วประเภทอื่น ๆ ล่ะ? NoneTypeตัวอย่างเช่นผมไม่สามารถทำซ้ำ


งานนี้type(obj) == str
โจชัววาร์เกเซ

คำตอบ:


241
isinstance()

ในกรณีของคุณจะกลับมาisinstance("this is a string", str)True

คุณอาจต้องการอ่านสิ่งนี้: http://www.canonical.org/~kragen/isinstance/


4
ผมว่าคุณ (OP) ที่ควรแน่นอนอ่านลิงค์อ้างอิงซึ่งจะช่วยให้ความอุดมสมบูรณ์ของรายละเอียดว่าทำไมการตรวจสอบชนิดของวัตถุมักจะเป็นความคิดที่ดีและสิ่งที่คุณอาจจะต้องทำแทน
เจฟฟ์นอน

2
คุณควรใช้ basestr ไม่ใช่ str มิฉะนั้นคุณจะไม่เลือก Unicode (แม้ว่าสำหรับ 3.x ฉันคิดว่า str เป็น basestr)
hasen

36

isinstance การทำงาน:

if isinstance(obj, MyClass): do_foo(obj)

แต่โปรดจำไว้ว่า: ถ้ามันดูเหมือนเป็ดและถ้ามันดูเหมือนเป็ดมันก็เป็นเป็ด

แก้ไข: สำหรับประเภทไม่มีคุณสามารถทำได้:

if obj is None: obj = MyClass()

def distance_from_zero(n): if isinstance(n,int) or isinstance(n,float): return abs(n) else: return "Nope" print distance_from_zero(True) ส่งกลับค่า "1" แทน "Nope" ทำอย่างไรจึงจะได้สิ่งนี้
dig_123

หากคุณต้องการใช้isinstanceแต่ตรวจสอบNoneแล้วยังใช้isinstance(obj, (MyClass, type(None)))งานได้ types.NoneTypeถูกลบออกจาก Python 3 แล้วดังนั้นจึงไม่สามารถพกพาtype(None)ไปอ้างอิงNoneTypeได้
Santeri Paavolainen

33

ก่อนอื่นให้หลีกเลี่ยงการเปรียบเทียบทุกประเภท พวกมันจำเป็นมาก ๆ บางครั้งพวกเขาช่วยตรวจสอบประเภทพารามิเตอร์ในฟังก์ชั่น - แม้จะหายาก ข้อมูลประเภทที่ไม่ถูกต้องจะเพิ่มข้อยกเว้นและนั่นคือทั้งหมดที่คุณต้องการ

ฟังก์ชั่นการแปลงพื้นฐานทั้งหมดจะแมปเท่ากับฟังก์ชั่นประเภท

type(9) is int
type(2.5) is float
type('x') is str
type(u'x') is unicode
type(2+3j) is complex

มีอีกหลายกรณี

isinstance( 'x', basestring )
isinstance( u'u', basestring )
isinstance( 9, int )
isinstance( 2.5, float )
isinstance( (2+3j), complex )

ไม่มี BTW ไม่ต้องการการตรวจสอบประเภทนี้อีกเลย None เป็นเพียงตัวอย่างของ NoneType วัตถุไม่มีเป็นแบบซิงเกิล เพียงตรวจสอบไม่มี

variable is None

BTW ห้ามใช้สิ่งเหล่านี้โดยทั่วไป ใช้ข้อยกเว้นสามัญและความแตกต่างตามธรรมชาติของไพ ธ อน


3
หากคุณกำลังตรวจสอบปัจจัยการผลิตจาก DSL NoneTypeคุณต้องการทั้งหมดนี้แม้ เกิดอะไรขึ้นถ้าพารามิเตอร์สามารถเป็นstr, unicodeหรือNone? มากสะอาดกว่าการตรวจสอบisinstance(x, (str, unicode, types.NoneType)) Noneหากคุณกำลังสร้างเครื่องมือสำหรับการคำนวณที่เลื่อนออกไปหรือหากคุณกำลังจะเปิดตัวกระบวนการที่ใช้เวลานานหรือใช้ทรัพยากรมากมันมีประโยชน์ที่จะตรวจจับtypeข้อผิดพลาดล่วงหน้าในระหว่างขั้นตอนการตรวจสอบความถูกต้องที่กำหนดเอง นี่เป็นส่วนสำคัญของโครงการคำนวณทางวิทยาศาสตร์เกือบทุกโครงการที่ฉันเคยทำ จากโครงการพัฒนาทั้งหมดที่ฉันเคยเห็นมีความต้องการมากกว่านี้
ely

23

สำหรับประเภทอื่น ๆ ตรวจสอบโมดูลประเภท :

>>> import types
>>> x = "mystring"
>>> isinstance(x, types.StringType)
True
>>> x = 5
>>> isinstance(x, types.IntType)
True
>>> x = None
>>> isinstance(x, types.NoneType)
True

PS Typechecking เป็นความคิดที่ไม่ดี


15

คุณสามารถใช้type(x) == type(y)เคล็ดลับซึ่งyเป็นประเภทที่รู้จักกันเสมอ

# check if x is a regular string
type(x) == type('')
# check if x is an integer
type(x) == type(1)
# check if x is a NoneType
type(x) == type(None)

บ่อยครั้งที่มีวิธีที่ดีกว่าในการทำเช่นนั้นโดยเฉพาะกับงูใหญ่ตัวล่าสุด แต่ถ้าคุณต้องการจำเพียงสิ่งเดียวคุณก็สามารถจำได้

ในกรณีนี้วิธีที่ดีกว่าคือ:

# check if x is a regular string
type(x) == str
# check if x is either a regular string or a unicode string
type(x) in [str, unicode]
# alternatively:
isinstance(x, basestring)
# check if x is an integer
type(x) == int
# check if x is a NoneType
x is None

หมายเหตุกรณีที่ผ่านมา: มีเพียงหนึ่งตัวอย่างของในหลามและนั่นคือNoneType Noneคุณจะเห็น NoneType เป็นจำนวนมากยกเว้น ( TypeError: 'NoneType' object is unsubscriptable- เกิดขึ้นกับฉันตลอดเวลา .. ) แต่คุณแทบจะไม่จำเป็นต้องอ้างถึงในรหัส

ในที่สุดเมื่อ fengshaun ชี้ให้เห็นการพิมพ์แบบหลามไม่ใช่ความคิดที่ดีเสมอไป มันเป็นแบบ pythonic มากกว่าเพียงแค่ใช้ค่าราวกับเป็นประเภทที่คุณคาดหวังและจับข้อยกเว้น (หรืออนุญาตให้เผยแพร่) ที่เป็นผลมาจากมัน


1
สำหรับสิ่งที่มีค่า isinstance () เป็นวิธีการตรวจสอบประเภทที่ต้องการใน Python (เมื่อคุณต้องทำ)
David Z

6

คุณสนิทมาก! stringเป็นโมดูลไม่ใช่ประเภท คุณอาจต้องการเปรียบเทียบประเภทของobjกับวัตถุประเภทสำหรับสตริงคือstr:

type(obj) == str  # this works because str is already a type

อีกวิธีหนึ่งคือ:

type(obj) == type('')

หมายเหตุใน Python 2 ถ้าobjเป็น unicode จะไม่สามารถใช้งานได้ isinstance()หรือจะ ดูความเห็นของจอห์นต่อโพสต์นี้เพื่อดูว่าต้องทำอย่างไรต่อไปนี้ ... ฉันพยายามจะจำมันได้ประมาณ 10 นาทีแล้ว แต่มีบล็อกหน่วยความจำอยู่!


2
ใช้ basestring กับ isinstance () เพื่อรับทั้ง str และ unicode
John Fouhy

5

เป็นเพราะคุณต้องเขียน

s="hello"
type(s) == type("")

type ยอมรับอินสแตนซ์และคืนค่าประเภท ในกรณีนี้คุณต้องเปรียบเทียบสองประเภท

หากคุณจำเป็นต้องทำการตรวจสอบแบบ preemptive จะเป็นการดีกว่าถ้าคุณตรวจสอบหาส่วนต่อประสานที่รองรับได้

ประเภทไม่ได้บอกอะไรคุณมากนักนอกจากความจริงที่ว่าโค้ดของคุณต้องการอินสแตนซ์ของประเภทเฉพาะโดยไม่คำนึงถึงความจริงที่ว่าคุณสามารถมีอินสแตนซ์อื่นที่มีประเภทแตกต่างกันโดยสิ้นเชิง .

ตัวอย่างเช่นสมมติว่าคุณมีรหัสนี้

def firstElement(parameter):
    return parameter[0]

ตอนนี้สมมติว่าคุณพูดว่า: ฉันต้องการให้รหัสนี้ยอมรับ tuple เท่านั้น

import types

def firstElement(parameter):
    if type(parameter) != types.TupleType:
         raise TypeError("function accepts only a tuple")
    return parameter[0]

นี่คือการลดการนำมาใช้ซ้ำของกิจวัตรนี้ มันจะไม่ทำงานถ้าคุณผ่านรายการหรือสตริงหรือ numpy.array สิ่งที่ดีกว่าจะเป็น

def firstElement(parameter):
    if not (hasattr(parameter, "__getitem__") and callable(getattr(parameter,"__getitem__"))):
        raise TypeError("interface violation")
    return parameter[0]

แต่ไม่มีประโยชน์ในการทำเช่นนั้น: พารามิเตอร์ [0] จะเพิ่มข้อยกเว้นหากโปรโตคอลไม่เป็นที่พอใจอย่างไรก็ตามแน่นอนว่าถ้าคุณต้องการป้องกันผลข้างเคียงหรือไม่ต้องกู้จากการโทรที่คุณสามารถเรียกใช้ก่อนที่จะล้มเหลว ตัวอย่าง (Stupid) เพียงเพื่อให้ประเด็น:

def firstElement(parameter):
    if not (hasattr(parameter, "__getitem__") and callable(getattr(parameter,"__getitem__"))):
        raise TypeError("interface violation")
    os.system("rm file")
    return parameter[0]

ในกรณีนี้รหัสของคุณจะยกข้อยกเว้นก่อนเรียกใช้ระบบ () โทร หากไม่มีการตรวจสอบส่วนต่อประสานคุณจะลบไฟล์ออกแล้วยกข้อยกเว้น


ขอบคุณที่ระบุวิธีที่ต้องการจริงเพื่อตรวจสอบอินเทอร์เฟซ คำตอบมากมายที่นี่พูดถึง แต่มีเพียงไม่กี่ตัวอย่างที่ให้สิ่งที่ดีแทน มันยังไม่ตอบคำถามส่วนตัวของฉันโดยตรง (ฉันพยายามแยกรายการสตริงที่มีหลายรายการที่มีความหมายจากสตริงซึ่งมีหลายรายการที่ไม่ได้มีความหมายขอบคุณ!
Nick


4

ฉันใช้ type(x) == type(y)

ตัวอย่างเช่นถ้าฉันต้องการตรวจสอบบางอย่างเป็นอาร์เรย์:

type( x ) == type( [] )

ตรวจสอบสตริง:

type( x ) == type( '' ) or type( x ) == type( u'' )

หากคุณต้องการตรวจสอบกับไม่มีใช้เป็น

x is None

ฮะ? เหตุใดจึงเป็นความคิดที่ไม่ดีโดยทั่วไป เป็นเพียงความคิดที่ไม่ดีสำหรับสตริง (สำหรับ 3.0 ก่อน) เนื่องจากมีสองประเภทของสตริง, str และ unicode สำหรับอาร์เรย์มันเป็นความคิดที่ดี
hasen

@hasen: มันเป็นความคิดที่ไม่ดีโดยรวม ถ้าฉันกำหนดประเภทของตัวเองที่ทำตัวเหมือนอาเรย์ แต่จะเอาค่าออกมาจากฐานข้อมูล รหัสของคุณจะล้มเหลวกับประเภทของฉันโดยไม่มีเหตุผล
nosklo

@hasen: อ่านลิงก์canonical.org/~kragen/isinstanceของคำตอบที่ได้รับการโหวตมากที่สุด (+7) คำตอบโดย voltronw
nosklo

1
เหตุผลทั้งหมด (สำหรับฉันอย่างน้อย) ในการตรวจสอบประเภทเป็นเพราะฉันต้องการจัดการกับอาร์เรย์ที่แตกต่างจากประเภทอื่น ๆ (รวมถึงประเภทที่เลียนแบบอาร์เรย์)
hasen

2
คุณผิด. ฉันจะให้ตัวอย่างที่เป็นรูปธรรม: django มีทางลัดการแสดงเทมเพลตที่สามารถยอมรับสตริงหรืออาร์เรย์ของสตริงได้ ตอนนี้ทั้งสตริงและอาร์เรย์ (รายการ) สามารถทำซ้ำได้ แต่ในกรณีนี้ฟังก์ชั่นจะต้องแยกความแตกต่างระหว่างพวกเขา
hasen


2

ประเภทใช้ไม่ได้กับบางคลาส หากคุณไม่แน่ใจเกี่ยวกับประเภทของวัตถุให้ใช้__class__วิธีการดังนี้:

>>>obj = 'a string'
>>>obj.__class__ == str
True

ดูบทความนี้ - http://www.siafoo.net/article/56


2

ในการรับชนิดใช้__class__สมาชิกเช่นเดียวกับในunknown_thing.__class__

พูดถึงการพิมพ์เป็ดไม่มีประโยชน์ที่นี่เพราะมันไม่ได้ตอบคำถามที่ดีอย่างสมบูรณ์ ในรหัสแอปพลิเคชันของฉันฉันไม่จำเป็นต้องรู้ประเภทของสิ่งใด แต่ก็ยังมีประโยชน์ในการเรียนรู้ประเภทของวัตถุ บางครั้งฉันต้องได้รับชั้นเรียนจริงเพื่อตรวจสอบการทดสอบหน่วย การพิมพ์เป็ดเข้าทางเพราะวัตถุที่เป็นไปได้ทั้งหมดมี API เดียวกัน แต่มีเพียงหนึ่งอย่างถูกต้อง นอกจากนี้บางครั้งฉันก็รักษารหัสของคนอื่นและฉันก็ไม่รู้เหมือนกันว่าวัตถุชนิดใดที่ฉันเคยผ่าน นี่คือปัญหาที่ใหญ่ที่สุดของฉันกับภาษาที่พิมพ์แบบไดนามิกเช่น Python เวอร์ชัน 1 นั้นง่ายและรวดเร็วในการพัฒนา เวอร์ชัน 2 เป็นความเจ็บปวดในขนมปังโดยเฉพาะอย่างยิ่งถ้าคุณไม่ได้เขียนเวอร์ชัน 1 ดังนั้นบางครั้งเมื่อฉันทำงานกับฟังก์ชั่นที่ฉันไม่ได้เขียนฉันจำเป็นต้องรู้ประเภทของพารามิเตอร์

นั่นคือสิ่งที่__class__พารามิเตอร์มีประโยชน์ นั่น (เท่าที่ฉันสามารถบอกได้) เป็นวิธีที่ดีที่สุด (อาจเป็นวิธีเดียว) ในการรับชนิดของวัตถุ


2

isinstance(object, type)ใช้ ดังกล่าวข้างต้นนี้ใช้งานง่ายถ้าคุณรู้ว่าถูกต้องtypeเช่น

isinstance('dog', str) ## gives bool True

แต่สำหรับวัตถุที่ลึกลับกว่านี้อาจเป็นเรื่องยากที่จะใช้ ตัวอย่างเช่น:

import numpy as np 
a = np.array([1,2,3]) 
isinstance(a,np.array) ## breaks

แต่คุณสามารถทำเคล็ดลับนี้:

y = type(np.array([1]))
isinstance(a,y) ## gives bool True 

ดังนั้นผมจึงขอแนะนำให้ instantiating ตัวแปร ( yในกรณีนี้) กับชนิดของวัตถุที่คุณต้องการตรวจสอบ (เช่นtype(np.array())) isinstanceแล้วใช้


0

คุณสามารถเปรียบเทียบชั้นเรียนสำหรับระดับการตรวจสอบ

#!/usr/bin/env python
#coding:utf8

class A(object):
    def t(self):
        print 'A'
    def r(self):
        print 'rA',
        self.t()

class B(A):
    def t(self):
        print 'B'

class C(A):
    def t(self):
        print 'C'

class D(B, C):
    def t(self):
        print 'D',
        super(D, self).t()

class E(C, B):
    pass

d = D()
d.t()
d.r()

e = E()
e.t()
e.r()

print isinstance(e, D) # False
print isinstance(e, E) # True
print isinstance(e, C) # True
print isinstance(e, B) # True
print isinstance(e, (A,)) # True
print e.__class__ >= A, #False
print e.__class__ <= C, #False
print e.__class__ <  E, #False
print e.__class__ <= E  #True
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.