Understanding isinstance()
on Python classes
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
.
|
|