Python learning metaclass

1. What is a metaclass

What is a metaclass? Everything comes from a sentence: everything in Python is an object. Let us first define a class and then analyze it step by step

class StanfordTeacher(object):
    school='Stanford'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s says welcome to the Stanford to learn Python' %self.name)

All objects are obtained by instantiating or calling the class (the process of calling the class is called class instantiation), for example, the object t1 is obtained by calling the class StanfordTeacher.

StanfordTeacher = t1 ( ' Lili ' , 18 is )
 Print (type (t1)) # view object class is t1 <class '__main __. StanfordTeacher' >

If everything is an object, then the class StanfordTeacher is essentially an object. Since all objects are obtained by calling the class, then StanfordTeacher must also be obtained by calling a class. This class is called a metaclass.

So we can deduce ===> the process of generating StanfordTeacher must have happened: StanfordTeacher = metaclass (...)

Print (type (StanfordTeacher)) # result is <class 'type'>, proved to be called the metaclass of this type produced StanfordTeacher, i.e., a default metaclass is type

From the above, the metaclass is the class used to instantiate the generated class.

Relationship: Metaclass --------> Instantiation ---------> Class -----------> Instantiation ------------ > Object

 

2. The steps required by the class keyword to create a class

In the above, we analyzed based on the concept that everything in Python is an object: the class we define with the class keyword is itself an object, and the class responsible for generating the object is called a metaclass (metaclass can be referred to as a class of classes), The built-in metaclass is type

When the class keyword helps us create a class, it must help us call the metaclass StanfordTeacher = type (...). What are the parameters passed in when calling type? Must be a key component of a class, a class has three major components, namely

1、类名class_name='StanfordTeacher'

2. The base classes class_bases = (object,)

3. The class name space class_dic, the name space of the class is obtained by executing the class body code

When calling type, the above three parameters will be passed in sequence

In summary, the class keyword to help us create a class should be subdivided into the following four processes

  1. Get the class name

  2. Get the base class of the class

  3. Execute the class body code and get the class namespace

  4. Call the metaclass to get the class

Supplement the usage of exec:

# exec: three parameters 

# parameter one: a string containing a series of python codes 

# parameter two: global scope (dictionary form), if not specified, the default is globals () 

# parameter three: local scope ( a dictionary), if not specified, the default is about locals () 

# can execute the exec command is executed as a function of the name will be generated during execution stored in the local name space 
G = {
     ' X ' :. 1 ,
     ' y ' : 2 
} 
l = {} 

exec ( ' '' 
global x, z 
x = 100 
z = 200 

m = 300 
'' ' , g, l) 

print (g) # {' x ': 100,' y ' : 2, 'z': 200, ......} 
print (l) # {'m': 300}

 

Three. Custom metaclasses to control the generation of classes

A class does not declare its metaclass. By default, its metaclass is type. In addition to using the built-in metaclass type, we can also customize the metaclass by inheriting type, and then use the metaclass keyword parameter to specify the metaclass for a class.

class Mymeta (type): # only class inherits the class type is the metaclass 
    #             empty object, "People", (), {...} 
    DEF  the __init__ (Self, X, Y, Z):
         Print ( ' run22222222222 .... ' )
         print (self)
         # print (x) 
        # print (y) 
        # print (z) 
        # print (y) 
        # if not x.istitle (): 
        #      raise NameError (' The first letter of the class name must be capital ah !!! ') 

    #           class is currently located, call the class when the argument passed 
    DEF  __new__ (CLS, * args, ** kwargs):
         # -made objects Mymeta 
        Print ('run1111111111.....')
        # print(cls,args,kwargs)
        # return super().__new__(cls,*args, **kwargs)
        return type.__new__(cls,*args, **kwargs)

Three things happen when calling Mymeta, calling Mymeta is type .__ call__

  1. First create an empty object and call the __new__ method in the Mymeta class

  2. Call the __init__ method in the Mymeta class to complete the operation of initializing the object

  3. Return the initialized object

class People(metaclass=Mymeta):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s:%s' %(self.name,self.name))

Emphasis: As long as the class is called, it will be called at once: __new__ in the class and __init__ in the class.

 

Four. Custom metaclass control class call (generation of class objects)

Reserve knowledge: __call__

class Foo:
     def  __call__ (self, * args, ** kwargs):
         print (self)
         print (args)
         print (kwargs) 

obj = Foo ()
 # 1, if you want the object obj to become a callable object, You need to define a method __call__ method in the class of the object, which will be automatically triggered when the object is called 
# 2. The return value of calling obj is the return value of the __call__ method 
res = obj (1,2,3, x = 1, y = 2)
# Applications: If you want an object can call parentheses, you need to add a method to the class of the object in __call__ 
# Summary: 
# Object () -> __call__ in class 
# class () -> Customize metaclass the __call__ 
# custom metaclass () -> built metaclass __call__
class Mymeta (type): # Only inherited type of class is the class metaclass 
    DEF  __call__ (Self, * args, ** kwargs):
         # 1, within Mymeta .__ call__ function will first call __new__ in the People 
        people_obj = self. __new__ (self)
         # 2, Mymeta .__ call__ function will call __init__ 
        self in People . __init__ (people_obj, * args, ** kwargs) 

        # print ('attribute of people object:', people_obj .__ dict__) 
        people_obj. __dict__ [ ' xxxxx ' ] = 11111
         # 3. Mymeta .__ call__ function will return an initialized object 
        return people_obj
# 类 的生产
# People = Mymeta () =》 type .__ call __ => Did 3 things 
# 1, type .__ call__ function will first call __new__ in Mymeta 
# 2, type .__ call__ function will be called __Init__ in Mymeta 
# 3, type .__ call__ function will return an initialized object

 

class People(metaclass=Mymeta):
    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s:%s' %(self.name,self.name))

    def __new__(cls, *args, **kwargs):
        # 产生真正的对象
        return object.__new__(cls)
obj1=People('egon',18)
obj2=People('egon',18)
# print(obj)
print(obj1.__dict__)
print(obj2.__dict__)
# 类 的应用
# obj = People ('egon', 18) = "Mymeta .__ call __ =" did 3 things 
# 1, Mymeta .__ call__ function will first call __new__ in People 
# 2, Mymeta .__ call_ _The function will call __init__ in People 
# 3, Mymeta .__ call__ function will return an initialized object

 

V. Attribute search

After learning metaclasses, in fact, the classes we customize with class are all objects (including the object class itself is also an instance of metaclass type, which can be viewed with type (object)). Considering the class as an object, the following inheritance should be said to be: the object StanfordTeacher inherits the object Foo, the object Foo inherits the object Bar, and the object Bar inherits the object object

class Mymeta (type): # Only inherited type class can be called a metaclass, otherwise, it is a common custom class 
    the n-444 = DEF __call__ (Self, * args, ** kwargs): # Self = <class' __main __. StanfordTeacher '> 
        obj = self. __new__ (self) 
        self. __init__ (obj, * args, ** kwargs)
         return obj class Bar (object): 
    n = 333 class Foo (Bar): 
    n = 222 class StanfordTeacher (Foo , metaclass = Mymeta): 
    n = 111 
    school = ' Stanford ' def

     








     the __init__ (Self, name, Age): 
        the self.name = name 
        self.age = Age 

    DEF say (Self):
         Print ( ' % S (Pic) available for purchase to the Python The Stanford to Learn ' % the self.name) 


Print (StanfordTeacher.n) # Bottom-up annotate n = xxx in each class in turn, and then re-run the program, found that the search order of n is StanfordTeacher-> Foo-> Bar-> object-> Mymeta-> type

Therefore, the attribute search should be divided into two layers, one layer is the object layer (MRO based on c3 algorithm) search, and the other layer is the class layer (metaclass layer) search

 

# Search order: 
# 1, the first object layer: StanfordTeacher-> foo-> Bar-> Object 
# 2, then the metaclass Layer: Mymeta-> type

Based on the above summary, let's analyze the search for self .__ new__ in __call__ in the metaclass Mymeta.

class Mymeta(type): 
    n=444

    def __call__(self, *args, **kwargs): #self=<class '__main__.StanfordTeacher'>
        obj=self.__new__(self)
        print(self.__new__ is object.__new__) #True


class Bar(object):
    n=333

    # def __new__(cls, *args, **kwargs):
    #     print('Bar.__new__')

class Foo(Bar):
    n=222

    # def __new__(cls, *args, **kwargs):
    #     print('Foo.__new__')

class StanfordTeacher(Foo,metaclass=Mymeta):
    n=111

    school='Stanford'

    def __init__(self,name,age):
        self.name=name
        self.age=age

    def say(self):
        print('%s says welcome to the Stanford to learn Python' %self.name)


    # def __new__(cls, *args, **kwargs):
    #     print('StanfordTeacher.__new__')


StanfordTeacher('lili',18) #Trigger the execution of the __call__ method in the StanfordTeacher class, and then execute self .__ new__ to start the search

To sum up, self .__ new__ in __call__ under Mymeta will find __new__ in object if there is no __new__ in StanfordTeacher, Foo, Bar, and there is a __new__ by default in object, So even if the previous class has not implemented __new__, it will definitely find one in the object, it will not, and there is no need to find the metaclass Mymeta-> type to find __new__

class Mymeta (type): # Only inherited type class can be called a metaclass, otherwise, it is a common custom class 
    the n-444 = DEF __new__ (CLS, * args, ** kwargs): 
        obj = type. __new__ ( CLS, * args, ** kwargs) # must follow this by value Print (obj. __dict__ )
         # return obj # only if the return value is the type of object that will trigger the following __init__ return 123 DEF __init__ (Self , class_name, class_bases, class_dic):
         print ( ' run ... ' ) class StanfordTeacher (object, metaclass = Mymeta): #

     
        
        

     


= Mymeta StanfordTeacher ( 'StanfordTeacher', (Object), {...}) 
    n-= 111 

    School = ' Stanford ' 

    DEF  the __init__ (Self, name, Age): 
        the self.name = name 
        self.age = Age 

    DEF say (Self ):
         Print ( ' % S (Pic) available for purchase to the Python the Stanford to Learn ' % the self.name) 


Print (type (Mymeta)) # <class 'type'> 
# procedure is generated based StanfordTeacher call Mymeta, but also the type Mymeta An object of the class, then the reason why Mymeta can be called, there must be a __call__ method in the metaclass type 
# This method also needs to do at least three things: 
#class type: 
#      def __call __ (self, * args, ** kwargs): # self = <class '__main __. Mymeta'> 
#          obj = self .__ new __ (self, * args, ** kwargs) # generate an object of Mymeta 
#          self .__ init __ (obj, * args, ** kwargs) 
#          return obj

 

Guess you like

Origin www.cnblogs.com/imark7/p/12709918.html