我想测试对象是否是类的实例,并且只测试此类(没有子类)。我可以用以下方式做到:
obj.__class__ == Foo
obj.__class__ is Foo
type(obj) == Foo
type(obj) is Foo
是否有理由选择一个而不是另一个? (表现差异,陷阱等)
换句话说:a)使用__class__
和type(x)
之间是否存在实际差异? b)使用is
更新:感谢大家的反馈。我仍然对类对象是否是单身人士感到困惑,我的常识说他们是,但是很难得到确认(尝试谷歌搜索“python”,“class”和“unique”或“singleton”)
我还想澄清一下,对于我的特殊需求,“更便宜”的解决方案才是最好的,因为我正在尝试优化一些专业课程中的大部分(几乎达到了这一点)理所当然的事情是放弃Python并在C)中开发该特定模块。但问题背后的原因是为了更好地理解语言,因为它的某些功能对于我来说很容易找到这些信息。这就是为什么我让讨论延伸一点而不是为__class__ is
解决,所以我可以听到更有经验的人的意见。到目前为止,它已经非常富有成效!
我进行了一项小测试,以测试4种替代方案的性能。分析器结果如下:
Python PyPy (4x)
type() is 2.138 2.594
__class__ is 2.185 2.437
type() == 2.213 2.625
__class__ == 2.271 2.453
不出所料,is
在所有情况下均优于==
。 type()
在Python中表现更好(快2%),__class__
在PyPy中表现更好(快6%)。有趣的是,__class__ ==
在PyPy中的表现优于type() is
。
更新2:很多人似乎都不明白我的意思“一个班级是一个单身人士”,所以我会用一个例子说明:
>>> class Foo(object): pass
...
>>> X = Foo
>>> class Foo(object): pass
...
>>> X == Foo
False
>>> isinstance(X(), Foo)
False
>>> isinstance(Foo(), X)
False
>>> x = type('Foo', (object,), dict())
>>> y = type('Foo', (object,), dict())
>>> x == y
False
>>> isinstance(x(), y)
False
>>> y = copy.copy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
>>> y = copy.deepcopy(x)
>>> x == y
True
>>> x is y
True
>>> isinstance(x(), y)
True
如果存在类型为type
的N个对象并不重要,给定一个对象,只有一个将是它的类,因此在这种情况下比较引用是安全的。由于参考比较总是比价值比较便宜,我想知道我的断言是否成立。我得出的结论是,除非有人提出相反的证据。
答案 0 :(得分:28)
对于旧式课程,存在差异:
>>> class X: pass
...
>>> type(X)
<type 'classobj'>
>>> X.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: class X has no attribute '__class__'
>>> x = X()
>>> x.__class__
<class __main__.X at 0x171b5d50>
>>> type(x)
<type 'instance'>
新式课程的目的是统一课程和类型。从技术上讲,__class__
是唯一适用于新旧类实例的解决方案,但它也会在旧式类对象本身上引发异常。您可以在任何对象上调用type()
,但不是每个对象都有__class__
。此外,您可以使用__class__
以type()
进行捣乱。
>>> class Z(object):
... def __getattribute__(self, name):
... return "ham"
...
>>> z = Z()
>>> z.__class__
'ham'
>>> type(z)
<class '__main__.Z'>
就个人而言,我通常只有一个带有新式课程的环境,并且由于风格优先使用type()
,因为我通常更喜欢使用内置函数来使用魔术属性。例如,我还希望bool(x)
到x.__nonzero__()
。
答案 1 :(得分:11)
type()
的结果相当于新样式类中的obj.__class__
,使用is
进行比较时类对象不安全,而是使用==
。
对于新款式,此处的首选方式为type(obj) == Foo
。
正如Michael Hoffman在他的回答中指出的那样,新旧风格类别之间存在差异,因此对于向后兼容的代码,您可能需要使用obj.__class__ == Foo
。
对于那些声称isinstance(obj, Foo)
更可取的人,请考虑以下情况:
class Foo(object):
pass
class Bar(Foo):
pass
>>> obj = Bar()
>>> isinstance(obj, Foo)
True
>>> type(obj) == Foo
False
OP需要type(obj) == Foo
的行为,即使Foo
是Bar
的基类,它仍然是假的。
答案 2 :(得分:11)
is
只应用于身份检查,而不是类型检查(规则中有一个例外情况,您可以使用is
来检查单身人士)。
注意:我通常也不会使用type
和==
进行类型检查。类型检查的首选方法是isinstance(obj, Foo)
。如果你有理由检查某些东西是不是一个子类实例,它对我来说就像一个腥味的设计。当class Foo(Bar):
时,Bar
是 Foo
,您应该避免任何代码的某些部分必须在{{1}上工作的情况实例但在Foo
实例上中断。
答案 3 :(得分:-1)
更新:感谢大家的反馈。我仍然对类对象是否是单身人士感到困惑,我的常识说他们是,但是很难得到确认(尝试谷歌搜索“python”,“class”和“unique”或“singleton”)
我可以确认__instance__
是单身人士。这是证据。
>>> t1=File.test()
made class
>>> t2=File.test()
made class
>>> print t1.__class__()
made class
<File.test object at 0x1101bdd10>
>>> print t2.__class__()
made class
<File.test object at 0x1101bdd10>
正如您所看到的,t1
和t2
在内存中打印出相同的值,即使t1
和t2
在内存中的值不同。这就是证据。
>>> print t1
<File.test object at 0x1101bdc90>
>>> print t2
<File.test object at 0x1101bdcd0>
__instance__
方法仅在您使用class "name"(object):
时才存在。如果您使用经典样式类class "name":
,则不存在__instance__
方法。
这意味着你可能想要使用type
是最通用的,除非你知道事实实例确实存在。