Why doesn’t type() always return the real class in Python?

Viewed 87

In Python, the built-in function type() always returns the real class of an instance, except if the instance variable __class__ has been set and the class variable __class__ has not been set, in which case it returns the instance variable __class__. What is the rationale for this exception?

class X:
    pass

class A:
    __class__ = X

a = A()
print(type(a))      # prints <class '__main__.A'> (the real class)
print(a.__class__)  # prints <class '__main__.X'>
class X:
    pass

class Y:
    pass

class A:
    __class__ = X

a = A()
a.__class__ = Y
print(type(a))      # prints <class '__main__.A'> (the real class)
print(a.__class__)  # prints <class '__main__.Y'>
class X:
    pass

class A:
    pass

a = A()
a.__class__ = X
print(type(a))      # prints <class '__main__.X'> (NOT the real class)
print(a.__class__)  # prints <class '__main__.X'>
1 Answers

type does always return the real class. When you did

class X:
    pass

class A:
    pass

a = A()
a.__class__ = X

you changed the class of a. The default __class__ data descriptor, object.__dict__['__class__'], is tied to the actual class of an object, and setting __class__ changes the actual class.

You'll find that, for example, a now has the methods of an X instance instead of an A instance (except that you didn't write any methods).

On the other hand, when you did

class X:
    pass

class Y:
    pass

class A:
    __class__ = X

a = A()
a.__class__ = Y

you hid the default __class__ descriptor. Now the a.__class__ assignment doesn't find a descriptor, so it just sets a '__class__' entry in the instance dict instead of changing the instance's class.

Related