The relationship between type and object in python

I am reading http://blog.thedigitalcatonline.com/blog/2014/09/01/python-3-oop-part-5-metaclasses/#.Vv1T7zG1XGA , which contains:

Since in Python everything is an object, everything is an instance of a class, even classes. Well, a type is a class that is designed to receive classes. Therefore, remember this: an object is the base for each object, a type is a class of each type. Sounds puzzling? This is not your fault, do not worry. However, just to hit you with the final move, this is what Python is built on

>>> type(object) <class 'type'> >>> type.__bases__ (<class 'object'>,) 

I am having trouble understanding this issue. Can someone explain this relationship differently to make it more clear?

+6
source share
3 answers

The relationships between type(x) basically coincide with the result of x.__class__ :

 for obj in (object,type,1,str): assert type(obj) is obj.__class__ print("type(obj) and obj.__class__ gave the same results in all test cases") 

__bases__ denotes the bases from which the class is derived:

 class parent: pass class child(parent,int): pass print(child.__bases__) 

however, if you ask about the odd relationship between object and type :

 >>> isinstance(object, object) True >>> isinstance(type, type) True >>> isinstance(object, type) True >>> isinstance(type, object) True 

what is more related to the question of chicken and egg: first come?

The answer is PyObject , which is defined in C.

before an object or type is available to the python interpreter, their underlying mechanisms are defined in C, and instance checking is redefined after they are defined. (act as abstract classes, see PEP 3119 )

you can think of it as something like this python implementation:

 #this wouldn't be available in python class superTYPE(type): def __instancecheck__(cls,inst): if inst ==TYPE: return True else: return NotImplemented #for this demo class TYPE(type,metaclass=superTYPE): def __instancecheck__(cls,inst): if inst in (OBJECT,TYPE): return True else: return NotImplemented #for this demo class OBJECT(metaclass=TYPE): pass print(isinstance(TYPE,OBJECT)) print(isinstance(OBJECT,TYPE)) print(isinstance(TYPE,TYPE)) print(isinstance(OBJECT,OBJECT)) 

in fact, it can be better represented as:

 #this isn't available in python class superTYPE(type): def __instancecheck__(cls,inst): if inst in (TYPE,OBJECT): return True else: return NotImplemented #for this demo class OBJECT(metaclass=superTYPE): pass class TYPE(OBJECT): pass 

but if you want to know exactly how this works, you will need to look at the source code written in C.

+3
source

TL DR - maybe not. But I tried.

It is really strange and looks like turtles. In fact, I still have not delved into this arena, although it sounded fun and powerful. This explanation is confusing, as is the rest of the information on this page, but I feel that I have some enlightenment. Can I explain this, I'm not sure, but I will go.

Look at the turtles, first:

 >>> isinstance(type, object) True >>> isinstance(object, type) True 

Wait what?

How is an object instance of type when type is an instance of object ? This is similar to saying something like:

 class Parrot: pass ex = Parrot() isinstance(ex, Parrot) isinstance(Parrot, ex) 

Must be True both times. But obviously not. Even (as Tadh MacDonald-Jensen pointed out)

 >>> isinstance(type, type) True 

This should tell you that some kind of magic is happening behind the curtains. So for now, let me just completely forget about Python (I know why we would ever want to do such a terrible thing?)

In general, all computer programs are 1 and 0 (and, more precisely, this is just a bunch of logic gates and electrons for> ~ 2.5v and ~ 2.5v, but 0 and 1 are good enough) . If you wrote it in an assembly, the actual machine code, Python, C #, Java, Perl, whatever - they are all just bits.

If you write a class definition, this class is just a bit. An instance of this class is more bits. And a programming language, a compiler, and an interpreter are even more bits.

In the case of Python, it is a python interpreter that gives meaning to the bits that are our Python programs. As an interesting point, many of what we usually see as Python are actually written in Python (although most of them are C, for us they are the people of CPython, Java for Jython, etc.).

So now we come to this thing, which we call type and object . As noted in the article, they are special. So, we know that we can create a class, and then this class is an object:

 >>> class Confusion: pass ... >>> isinstance(Confusion, object) 

What makes sense if you think about it - you may have created class level variables:

 >>> class Counter: ... count = 0 ... def __init__(self): ... Counter.count += 1 ... print(self.count) ... >>> Counter() 1 <__main__.Counter object at 0x7fa03fca4518> >>> Counter() 2 <__main__.Counter object at 0x7fa03fca4470> >>> Counter() 3 <__main__.Counter object at 0x7fa03fca4518> >>> Counter() 4 <__main__.Counter object at 0x7fa03fca4470> >>> Counter.count 4 >>> Counter.__repr__(Counter) '<type object at 0x1199738>' 

But since this last example shows (and is mentioned in the message) a class declaration, what you get with class SomeClass: pass , then the class declaration is actually an instance of another class. In particular, it is an instance of the type class. And this instance (which we call the class), when called, produces an instance of itself:

 >>> Counter.__call__() 5 <__main__.Counter object at 0x7fa03fca4518> 

So, what does all this have to do with the relationship between type and object ?

Well somewhere, python creates a series of object bits and a sequence of type bits, and then connects them so that

 >>> type.__bases__ (<class 'object'>,) >>> object.__bases__ () 

Since I don’t want to look at the source now, I’m going to assume that type is created first, and object is created from this type and that type.__bases__ set to (class 'object') . By creating this circular relationship between type and object , it gives the appearance that it’s just turtles all the way down, when indeed the last two turtles just stand on top of each other.

I don’t think that there is a better way to explain what is happening here than what is described in the article - at least in the classical style of OOP there is a style of thinking, because in fact it is not a thing. Like trying to build a three-dimensional shape in 2d space, you will have problems.

These are just two sets of bits in which there are some bits inside them that are each other's addresses.

+1
source

Although my first answer is about the paradoxical relationship between type and object Python built-in variables, it does not necessarily try to clarify the confusion as to what exactly type and object mean in the big picture. This answer will explain how object and type affect other Python objects in a context that you are likely to see in practice.

In Python, everything is an object

This means that the isinstance(x, object) operator will always give True for any possible value of x .

It also means that any particular class will be considered a subclass of the object. So issubclass(x, object) always true for any class.

In practice, this means that operations that are standard for all Python objects will be defined in the object , such as searching for attributes and getting the size of the object in memory. It also defines behavior that is usually overridden, such as conversion to string or initialization, so if you don't override __str__ or __init__ in your subclass, it will still do something sensible.

type is a class that is created to receive classes

This means that all classes are considered instances of type . Therefore, isinstance(x, type) will be true for all classes. When I say classes, I mean things like int , str , bool or a variable created by the class keyword.

everything is an object - even classes.

This means that the standard behavior that exists for all objects also applies to class objects. Therefore, writing str.join will look for the join method and give you <method 'join' of 'str' objects>

type is a class of each type

in the same way that int defines what 1+3 should do, or str defines methods for strings, so type defines behavior specific to type objects. For example, calling an object of a class (for example, int("34") ) will create a new instance of this class - this behavior of creating new objects is defined in the type.__call__ .

As a more specific example, consider the duality between str.join and type.mro

 >>> x = "hello" >>> str.join # unbound method of strings <method 'join' of 'str' objects> >>> x.join #bound method of x <built-in method join of str object at 0x109bf23b0> >>> hex(id(x)) # the memory address of x as seen above '0x109bf23b0' >>> type.mro #unbound method <method 'mro' of 'type' objects> >>> int.mro #mro method bound to int <built-in method mro of type object at 0x106afeca0> >>> hex(id(int)) # address of int object as seen above '0x106afeca0' >>> int.mro() #mro stands for Method Resolution Order, is related to __bases__ [<class 'int'>, <class 'object'>] 

Thus, each class defines methods that act on its instances, the behavior of classes is determined in the type class.

The behavior that is common to all objects - the types of things that you usually simply attribute to be built-in - is determined by object so all objects share this behavior (unless a subclass cancels it :)

PS In the same way you can create a subclass of str to create special string objects with different behavior, you can create a subclass of type to create special classes with different behavior. This is called a meta class (class of a class object), and the practical application of meta classes is usually abstract . (pun intended)

0
source

All Articles