Difference between type(obj) and obj.__class__
type(obj)和obj.__class__有什么区别?有没有可能出现type(obj) is not obj.__class__?
我想编写一个在所提供对象上一般工作的函数,使用与另一个参数相同类型的默认值1。下面的哪一个变化,1或2,将做正确的事情?
1 2 3 4
| def f(a, b=None):
if b is None:
b = type(a)(1) # #1
b = a.__class__(1) # #2 |
这是一个古老的问题,但似乎没有一个答案提到这一点。在一般情况下,一个新类型的类可能对type(instance)和instance.__class__有不同的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class ClassA(object):
def display(self):
print("ClassA")
class ClassB(object):
__class__ = ClassA
def display(self):
print("ClassB")
instance = ClassB()
print(type(instance))
print(instance.__class__)
instance.display() |
输出:
1 2 3
| <class '__main__.ClassB'>
<class '__main__.ClassA'>
ClassB |
原因是ClassB正在重写__class__描述符,但是对象中的内部类型字段没有更改。type(instance)直接从该类型字段中读取,因此返回正确的值,而instance.__class__是指替换python提供的原始描述符的新描述符,后者读取内部类型字段。它不是读取内部类型字段,而是返回一个硬编码值。
- 注意:这应该作为一个例子来说明为什么你应该避免覆盖__class__!您可能会导致使用__class__的行中的代码中断。
- 也受__getattribute__的影响,后者截获了OBJ.__class__的请求,但没有截获type(OBJ)的请求。
- 有些代码故意这样做是为了掩盖对象的类型,比如weakref.proxy。有些人认为应该优先选择OBJ.__class__,因为它相信谎言,而有些人认为应该优先选择type(OBJ),因为它忽略了谎言。如果对象的实类或其Lie类是第二个参数的实例,则isinstance将返回true。
旧风格的课程是问题所在,叹息:
1 2 3 4 5 6 7 8
| >>> class old: pass
...
>>> x=old()
>>> type(x)
<type 'instance'>
>>> x.__class__
<class __main__.old at 0x6a150>
>>> |
在python 3中没有问题,因为所有类现在都是新样式;-)。
在python 2中,类只有从另一个新的样式类(包括object和各种内置类型(如dict、list、set…)继承,或者隐式或显式地将__metaclass__设置为type时,才是新样式。
- 是python 3次,我们应该用哪个?
- 如果您的代码遵循Alex描述的最佳实践,那么最好使用type()。在Python3中,它总是遵循最佳实践,所以在Python3中使用type()。
- @aaronhall如果我在编写python 2代码的时候知道它只能用新样式的类的实例来调用,那么我假设使用type()也比__class__更好吗?
- @是的,如果代码总是从对象继承,那么使用type()是安全的。
- @alex martelli@aaronhall内置函数type(instance)和属性instance.__class__可以不同,即使是新类型的类,正如pep 3119中提到的guido:"另外,isinstance(x, B)相当于issubclass(x.__class__, B) or issubclass(type(x), B)。(可能type(x)和x.__class__不是同一个对象,例如,当x是一个代理对象时。)"正如@flavien的回答所示。
对于旧式类,type(obj)和type.__class__的行为不同:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| >>> class a(object):
... pass
...
>>> class b(a):
... pass
...
>>> class c:
... pass
...
>>> ai=a()
>>> bi=b()
>>> ci=c()
>>> type(ai) is ai.__class__
True
>>> type(bi) is bi.__class__
True
>>> type(ci) is ci.__class__
False |
- 最大的讽刺是,亚尔舒的评论现在也有同样的问题,因为他们改变了格式。P
- 展示他们的行为方式和原因不会有什么坏处。当他们的行为有所不同时,即使回答正确,也只是一个懒惰的回答。
- 值得一提的是,这只是Python2中的问题。在python 3中,这三个表达式都是真的。