type(instance)
and instance.__class__
may be different, even with new-style classes, as Guido van Rossum mentioned in PEP 3119:
Also, isinstance(x, B)
is equivalent to issubclass(x.__class__, B) or issubclass(type(x), B)
. (It is possible type(x)
and x.__class__
are not the same object, e.g. when x
is a proxy object.)
For example, the function weakref.proxy
of the standard library creates proxy objects.
>>> import weakref
>>> class A: pass
...
>>> a = A()
>>> type(weakref.proxy(a))
<class 'weakproxy'>
>>> weakref.proxy(a).__class__
<class '__main__.A'>
>>> repr(weakref.proxy(a))
'<weakproxy at 0x10065ab30 to A at 0x1006534c0>'
Note that the implementation of the __repr__
method of the proxy object uses type(instance)
, not instance.__class__
, since the primary purpose the __repr__
method is to provide enough information to recreate the object when debugging.
type(instance)
The real class of an object
instance is stored on the instance in a __class__
slot (i.e. at a fixed offset in the instance layout). It can only be accessed through the data descriptor vars(object)['__class__']
(whose method __get__
allows attribute retrieval, whose method __set__
allows attribute assignment, and whose method __delete__
forbids attribute deletion), or equivalently through the built-in function type
(whose one-argument form allows attribute retrieval):
>>> class A: pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> vars(object)['__class__'].__get__(a)
<class '__main__.A'>
>>> class B: pass
...
>>> vars(object)['__class__'].__set__(a, B)
>>> type(a)
<class '__main__.B'>
>>> vars(object)['__class__'].__get__(a)
<class '__main__.B'>
>>> vars(object)['__class__'].__delete__(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't delete __class__ attribute
instance.__class__
If the data descriptor vars(object)['__class__']
is not overridden in an object
subclass, instance.__class__
accesses the real class of instance
through the data descriptor:
>>> class A: pass
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class '__main__.A'>
>>> class B: pass
...
>>> a.__class__ = B
>>> type(a)
<class '__main__.B'>
>>> a.__class__
<class '__main__.B'>
>>> del a.__class__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't delete __class__ attribute
But if the data descriptor vars(object)['__class__']
is overridden in an object
subclass, instance.__class__
does not access the real class of instance
. Moreover, if the override is not a data descriptor, it can itself be overridden in instance
:
>>> class A: __class__ = int # overrides vars(object)['__class__']
...
>>> a = A()
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>
>>> a.__class__ = str # overrides vars(A)['__class__'] (not a data descriptor)
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'str'>
>>> del a.__class__
>>> type(a)
<class '__main__.A'>
>>> a.__class__
<class 'int'>