Python type()或__class __,==或is

时间:2012-03-07 23:52:47

标签: python language-features

我想测试对象是否是类的实例,并且只测试此类(没有子类)。我可以用以下方式做到:

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个对象并不重要,给定一个对象,只有一个将是它的类,因此在这种情况下比较引用是安全的。由于参考比较总是比价值比较便宜,我想知道我的断言是否成立。我得出的结论是,除非有人提出相反的证据。

4 个答案:

答案 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的行为,即使FooBar的基类,它仍然是假的。

答案 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>

正如您所看到的,t1t2在内存中打印出相同的值,即使t1t2在内存中的值不同。这就是证据。

>>> print t1
<File.test object at 0x1101bdc90>
>>> print t2
<File.test object at 0x1101bdcd0>

__instance__方法仅在您使用class "name"(object):时才存在。如果您使用经典样式类class "name":,则不存在__instance__方法。

这意味着你可能想要使用type是最通用的,除非你知道事实实例确实存在。