Nailing down new-style classes and types in Python
Since I keep confusing myself, it's time to write this stuff down once and for all to make sure I have it straight (even if some or all of it is in the official documentation).
One writes Python code to define classes; it's right there in the
language syntax, where you write '
class A(object): ...'. Defining a
class creates a type object for that class, which is an instance of
type; this C-level object holds necessary information about the class
and how it's actually implemented. This type object is
what is bound to the class name; if you define a class
will then report
Classes have a class inheritance hierarchy, which is ultimately rooted
object (including for C-level classes). However, strictly speaking
there is no type hierarchy as far as I know; all types are simply
type itself). Further, the type
non-hierarchy is of course unrelated to the class hierarchy. This means
isinstance(A, type) is True but
issubclass(A, type) is both
False and the wrong question (unless you really do have a subclass of
type somewhere in your code).
(Among other things I believe that this means that '
is always '
type' for any arbitrary Python object, since all objects
have a type and all types are instances of
The Python documentation sometimes talks
about a 'type hierarchy'. What it means is either 'the conceptual
hierarchy of various built-in types', such as the various forms of
numbers, mutable sequences, and so on, or 'the class inheritance
hierarchy of built-in types', since a few are subclasses of others and
everyone is a subclass of
(Some languages really do have a hierarchy of all types, with real
(abstract) types for things like 'all numeric types' or 'all mutable
sequence types', but Python does not. You can see this by inspecting the
__mro__ attribute on built in types to see the classes involved in
their method resolution order; the MRO of a
int is just itself and
object. Only a few built in types
are subclasses of other types.)
PS: yes, almost all of this is in the Python documentation or is implied by it. Writing it down anyways helps me get it straight in my own head.
PPS: I believe that technically it would be possible for a sufficiently
perverse extension module to create a valid new style C-level class
that was not a subclass of
object. Don't do that, and if you did I
expect that things would blow up sooner or later.
Sidebar: the real difference between classes and types
If you use
repr() on user-defined classes and on built in types (eg
repr(A)' and '
repr(str)'), you'll notice that it reports them
differently. This is a bit odd once you think about it, since they are
both instances of
type and so are using the same
yet one reports it is a 'class' and the other reports it is a 'type'.
In CPython, the difference between the two is whether the C-level
type instance structure is flagged as having been allocated on the
heap or not. A heap-allocated type instance is a class as far as
type.__repr__() is concerned; a statically allocated one is a
type. All classes defined in Python are allocated on the heap, like all
other Python-created objects, and so report as classes. Most 'types'
defined in C-level extension modules are statically defined and so get
called types, but I believe that with sufficient work you could create a
C-level type that had a heap allocated type instance and was reported as
(It's easy enough to keep it from being garbage collected out from underneath your extension module; you just artificially increase its reference count.)