Understanding isinstance() on Python classes

January 16, 2012

Suppose that you have:

class A(object):
  pass

class B(A):
  pass

As previously mentioned, the type of classes is type, which is to say that class objects are instances of type:

>>> isinstance(A, type)
True
>>> isinstance(B, type)
True

Both A and B are clearly subclasses of object; A is a direct subclass and B is indirectly a subclass through A. In fact every new-style Python class is a subclass of object, since object is the root of the class inheritance tree. However, class type is not the same as class inheritance:

>>> issubclass(B, A)
True
>>> isinstance(B, A)
False

Although B is a subclass of A, it is not an instance of A; it is a direct instance of type (we can see this with 'type(B)'). Now, given that A and B are instances of type, one might expect that they would not be instances of object since they merely inherit from it, as B inherits from A:

>>> isinstance(A, object)
True

Well, how about that. We're wrong (well, I'm wrong, you may already have known the correct answer). Here is why:

>>> issubclass(type, object)
True

A and B are instances of type and, like all other classes and types, type is a subclass of object. So A and B are also instances of object (at least in an abstract, Python level view of things), in the same way that an instance of B would also be an instance of A.

I believe that this implies that 'isinstance(X, object)' is always true for anything involved in the new-style Python object system. The corollary is that this is an (almost) surefire test to see if the random object you are dealing with is an old style class or an instance of one:

class C:
  pass

>>> issubclass(C, object)
False
>>> isinstance(C, object)
False

(This goes away in Python 3, where there is only new-style classes and there is much rejoicing, along with people no longer having to explicitly inherit from object for everything.)

PS: as originally noted by Peter Donis on a comment here, object is also an instance of type because object is itself a class. type is an instance of itself in addition to being a subclass of object. Try not to think about the recursion too much.

(This isinstance() surprise is an easy thing to get wrong, which is why I'm writing it down; I almost made this mistake in another entry I'm working on.)

Sidebar: isinstance() and metaclasses

If A (or B) has a metaclass, it is an instance of the metaclass instead of a direct instance of type. In any sane Python program, 'isinstance(A, type)' will continue to be True because A's metaclass will itself be a subclass of type.

(I'm not even sure it's possible to create a working metaclass class that doesn't directly or indirectly subclass type (cf), but I'm not going to bet against it.)

This implies that I was dead wrong when I said, back in ClassesAndTypes, that 'type(type(obj))' would always be 'type' for any arbitrary Python object, as Daniel Martin noted at the time and I never acknowledged (my bad). In the presence of metaclasses, type(type(obj)) can be the metaclass instead of type itself. Since metaclasses can themselves have metaclasses, so there is no guarantee that any fixed number of type() invocations will wind up at type.

Written on 16 January 2012.
« What you can find out about the memory usage of your Linux programs
The first browser blinks on XHTML parsing »

Page tools: View Source, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Mon Jan 16 22:32:55 2012
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.