I had a question about what exactly is the class or object object
in Python.
As far as I know, in Python everything is created by the metaclass type
(but from what I will explain next it makes me doubt):
>>> str.__class__
<class 'type'>
>>> int.__class__
<class 'type'>
>>> bool.__class__
<class 'type'>
>>> float.__class__
<class 'type'>
>>> class A:
... pass
...
>>> A.__class__
<class 'type'>
>>> ClassName = type('ClassName', (), {})
>>> ClassName.__class__
<class 'type'>
On the other hand object
it is an instance of type
:
>>> object.__class__
<class 'type'>
>>> isinstance(object, type)
True
What doesn't work for me at all is this:
>>> isinstance(type, object)
True
How can it possibly type
be an instance of object
if it's supposed to object
be an instance of type
? Has no sense. Looks like Python is contradicting itself...
In addition to this, it object
is a base class of type
:
>>> type.__bases__
(<class 'object'>,)
But according to Python object
it is an instance of type
and according to that, how is it possible for a class ( type
) to inherit from an instance ( object
) of said class?
So based on this: What exactly is type
and object
? Which of the two is the "true" metaclass or "the class that creates classes" so to speak? As I understood it was type
:
type('MyClass', (), {})
And out of curiosity to know more about object, it seems that all classes inherit or descend from it:
>>> int.__bases__
(<class 'object'>,)
>>> bool.__bases__
(<class 'int'>,)
>>> str.__bases__
(<class 'object'>,)
>>> float.__bases__
(<class 'object'>,)
>>> class A:
... pass
...
>>> A.__bases__
(<class 'object'>,)
Why is it like this?
Perhaps a
goodsummary is:It is common that, when supporting OOP in a language, there is a metaclass from which the other classes derive and a root class from which all objects derive. For example, in Smalltalk there is
Class
andObject
respectively. Well, we could think that in Python its equivalents aretype
andobject
, but if, as mentioned above, everything is an object,type
it is also an object and therefore it should derive fromobject
. Sinceobject
it's a class, it should derive fromtype
... which brings us to a classic question in philosophy and which is your question in essence:Everything in Python revolves around the concept of "object", it's Python's abstraction for representing data. All data in Python is represented by objects or by relationships between them.
Every object has three characteristics:
An identity : it is unique to each object and never changes as long as it exists. In CPython the memory address of the object is used. It is what the identity operator (
is
) compares and what the builtinid()
returns.A value : the data represented by the object, the value can change in mutable objects like lists. In immutable objects such as strings cannot be modified after the instance of the object.
A type : The type (or class) of an object is the class of which it is an instance. A class is also an object and therefore has a type, the type of these objects is
type
. Ittype
is also an object and its type is alsotype
, the only object with this characteristic.Conceptually, since Python 2.2 "type" and "class" are the same.
object
The class
object
is the base of the class hierarchy in Python. All classes are subclasses of the class ofobject
, therefore all objects are instances ofobject
. This class contains the basic skeleton of a class, from it come the essential methods that every class has, such as__getattribute__
, methods that we can always call from a subclass to, for example in the case of '__getattribute__
', make it impossible for private attributes to exist in Python by much that we insist...Remember, that a class itself is also an object, an object stored in memory with the instructions to build other objects.
type
Defined in C (
PyObject* PyType_Type
), it is the only built-in metaclass in CPython. A metaclass is simply a class whose instances are also classes.Just as we affirm that everything is an object, everything has a type , yes,
object
also...but unlike
object
, not everything is a type (or derives fromtype
):Everything looks like a mess, it may seem that
type
andobject
mutually inherit from each other, but this is not really true, in fact this is intrinsically conceptually impossible in OOP. In addition, we must always keep in mind that we are moving at a level where OOP does not really exist, it is being created. CPython is implemented in C and C does not understand OOP. Neitherobject
inherits fromtype
nortype
fromobject
at this level, there is simply no inheritance.More than inheriting each other, what happens is that it
object
is an instance oftype
andtype
derives fromobject
. Indeed, there is still a cyclical relationship that is resolved at the C level in several steps and with several indirections in between that I am not going to go into.At the Python level, the small paragraph at the beginning of the answer must always be true to respect the data model:
type
it has to be an object to exist.object
it is the base type of all objects, it is a type and as a type it must be an instance oftype
.If we abstract away from all the implementation and conceptual details, we could be left to not disturb our existence with the following:
The base class for every object is
object
(other than its own ofobject
course), always, always, always:Every object has a type, which is simply the class of which it is an instance, so type and class are equivalent concepts. Very nice so far, but if every object has a type and a class is also an object, what type do we assign to a "class" object? This is precisely where it comes in
type
, it is the type of every "class" object, includingobject
andtype
itself.The class
type
exposed through the builtintype()
allows us to create new types/classes dynamically, as a good metaclass allows us to create instances that are classes, but does anyone guess at this point what is the base class of the classes ittype
generates for us?Always keep in mind the distinction between deriving/inheriting and being an instance of something. One thing is "being an instance of X" and quite another "being a class that derives from X":
foo
is an instance ofFoo
, but does not inherit from it, insteadBar
if it derives fromFoo
, but is not an instance of it.Summary
Every object except its own
object
derives fromobject
, otherwise it does not exist.The metaclass
type
as an object that exists, derives fromobject
.The metaclass
type
creates other classes that all, without exception, derive fromobject
.So it
object
doesn't derive/inherit from anything, buttype
it is an instance ofobject
.As much
object
astype
they are classes, then their type istype
, so ittype
is the only class in which the following is true:Therefore we can consider that a class/type is an instance of
type
and always derives fromobject
.What a most interesting question. I share my answer with reference to the official documentation of the language, but also based on my personal experience in the deepest point of your question.
Indeed, according to the language documentation, https://docs.python.org/3/library/functions.html#object , object
object
is an object of type class, and is a base for all other classes. That is why all classes, including those built into the language, such asint
,dict
,set
,list
, etc., have the object as one of their base classesobject
.Without a doubt, this is very confusing by virtue of the above. In my experience there is no contradiction: following the documentation, the object
object
is the class from which all the others derive; we can explore further, and we will find that ittype
is a subclass ofobject
,but it is not true that
object
it is a subclass oftype
. So,object
it is instance (instance) oftype
by design, to show that itobject
is a class (or else, an object of type class), and all classes are objects whose type istype
( https://docs.python.org/3/ reference/datamodel.html ), even ifobject
it doesn't get from theobject = type("object", bases=(), dict=some_dict)
. Analogously it happens withtype
.At this point there is no further confusion. The object
object
is the base of all classes, and contains the methods common to all instances of any class, even if these instances are classes themselves. When you call it in the formobject()
, it returns an object with no features or attributes ( https://docs.python.org/3/library/functions.html#object ), so it doesn't create classes. The objecttype
is a class, and therefore its type is itself:type
. Calling it with three arguments is a dynamic way to create a class instead of declaringclass
https://docs.python.org/3/library/functions.html#type . The class that creates classes istype
(is a metaclass), and so all classes are instances oftype
.