type
is the “type” that “types” inherit from. Any defined type is a type
, so isinstance(x, type)
is valid for any x
that is a type. – Confused yet? ^^
When you instantiate a type, you get an object of that type. That object is not necessarily a type; unless the type was a metaclass because instances of metaclasses are types (which I’m going to ignore here).
A
is a type. Types inherit from type
(by definition), and in the common case the metaclass for types is also type
. Instances of type
are types, so type
will be included in the method resolution order for the type instance A
. That is why e.g. calling A.mro()
works. mro()
is defined on type
and that method is inherited when the type instance A
gets created.
However note that A.mro()
gives you the method resolution order for instances of A
. Not for A
itself (the type instance).
You inherit object
because when instantiating an object of A
, that object should be instanceof(x, A)
and instanceof(x, object)
. But it is not a type because that would mean that you could instantiate it again. It is an object, so you should inherit from object (directly or indirectly).
A.__class__
gives you the type that was used to create the instance A
. If you do A().__class__
, you will get A
which is the type that was used to create the instance A()
.
object
is the base type for any object in Python. Everything is an object, so any object is a direct or indirect instance of object
. type
is the type of types that can be instantiated to create objects.
For information on why object
is a type
, and why type
is in turn an object
, see this answer.
For old-style classes, classobj
is the kind-of metaclass. Note that old-style classes have a very different object model, so you can only apply parts of the new-style mentality there. You should try to use only new-style classes now (or possibly even switch to Python 3) since the object model is a lot more consistent and in my opinion easier to reason about.