当type(instance)与instance.__class__不同时是什么情况?
当type(instance)与instance.__class__不同时是什么情况?
Python内置了一个名为`type`的函数:
class type(object) 使用一个参数,返回对象的类型。返回值是一个类型对象,通常与`object.__class__`返回的对象相同。
Python还有一个特殊的属性`__class__`:
instance.__class__ 类实例所属的类。
我曾经认为它们都指向同一个对象。然而,在方法`abc.ABCMeta.__instancecheck__`中有一个检查它们是否相同的语句:
def __instancecheck__(cls, instance): """Override for isinstance(instance, cls).""" # Inline the cache checking subclass = instance.__class__ # […] subtype = type(instance) if subtype is subclass: # […]
什么时候`type(instance)`与`instance.__class__`不同?
在Python中,当我们使用type(instance)和instance.__class__来获取一个对象的类型时,有时候会发现这两者的结果不同。这种情况通常出现在旧式对象(不继承任何类)中。这些对象没有__class__属性,我认为他们这样做是为了防止错误发生。
下面是一个Python 2.7的示例:
class A: pass class B(object): pass a = A() b = B() print(dir(a)) # ['__doc__', '__module__'] print(dir(b)) # ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] print(b.__class__) #print(type(b)) # # The interesting part print(a.__class__) # __main__.A print(type(a)) # print(B.__class__) # print(type(B)) # print(type(A)) # #print(A.__class__) # AttributeError: class A has no attribute '__class__'
从上面的例子中可以看出,当我们使用type(instance)和instance.__class__时,对于旧式类来说,结果是不同的。type(instance)返回的是
这种现象可以通过以下链接进一步了解:
- [Python type() or __class__, == or is](https://stackoverflow.com/questions/9610993)
- [NewClassVsClassicClass](https://wiki.python.org/moin/NewClassVsClassicClass)
- [Why does `type(myField)` return `
需要注意的是,这种行为在CPython中最后一次更改是在2008年(commit),所以这似乎是一个兼容性问题,或者他们只是忘记了这个问题。
值得一提的是,Python 3.x中已经没有旧式类了,因此这个问题在Python 3.x中不会出现。
在上述内容中,"When is type(instance) different from instance.__class__?"这个问题的出现原因是因为在某些情况下,type(instance)和instance.__class__可能会不同。例如,当对象是代理对象时,这两者可能不同。同时,解决这个问题的方法是使用isinstance(x, B)等价于issubclass(x.__class__, B) or issubclass(type(x), B)。此外,还可以使用vars(object)['__class__']来访问实例的真实类。
在上述内容中,type(instance)表示实例的真实类,存储在实例的__class__槽中。可以通过data descriptor vars(object)['__class__']或内置函数type来访问这个真实类。
instance.__class__表示实例的类。如果在object子类中没有重写data descriptor vars(object)['__class__'],那么instance.__class__会通过data descriptor访问实例的真实类。但是,如果在object子类中重写了data descriptor vars(object)['__class__'],那么instance.__class__将不会访问实例的真实类。此外,如果重写的data descriptor不是一个data descriptor,那么它可以被实例中的属性所重写。
type(instance)和instance.__class__之间可能不同的原因是实例的__class__槽被重写或实例是代理对象。解决这个问题的方法是使用isinstance(x, B)等价于issubclass(x.__class__, B) or issubclass(type(x), B)来判断实例的类。另外,可以使用vars(object)['__class__']来访问实例的真实类。