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'>