SoFunction
Updated on 2024-10-30

Metaclass metaclass details in python

locomotive

The python language is still on the surface because the work is biased towards AI, so there is no exposure to the python depths.

Today to talk about metaclass (metaclass), most people must have more or less heard of the word metaprogramming, but what is metaprogramming and how to apply metaprogramming should not be familiar with much, metaclass in python is to help developers to realize the metaprogramming, and therefore an idea!

I've had a lot of time on my hands lately, so I wanted the article to get serious.

Eliciting MetaClass from a question

There is no function overloading in the python language, which we illustrate below with a concrete example.

class A():
    def f(self, x:int):
        print(' int overload',self,x)
    def f(self,x:str):
        print(' str overload',self,x)
    def f(self,x,y):
        print(' two arg overload',self,x,y)
if __name__ == "__main__":
    a = A()
    (1)

When executing the above code we get an error message that after instantiating class A, the f method of the instance is called, and since there is no reload method in the python language, thedef f(self,x:str) will overwrite the previousdef f(self, x:int), anddef f(self,x,y) method overrides thedef f(self,x:str) method, so when passing in 1 parameter, it won't call thedef f(self,x:int) Instead, calldef f(self,x,y) Methods.

TypeError: f() missing 1 required positional argument: 'y'

So what is the right posture to solve this problem? There's no rush to give an answer here; it will emerge naturally after we've introduced metaclass.

Metaclass Programming

If you want to understand Metaclass, that is, meta class, meta in English means beyond, that is, Metaclass is higher than class, used to create the class of the class. sometimes we need to control the process of class creation, usually the work of creating the class is done by the type, because the type is designed directly to the c, and we want to insert some customized things into the class creation process by the type, so we introduced Metaclass to let a certain class creation work is no longer implemented by the type, but by the specified class. We want to insert some customization into the class creation process of type, so we introduce Metaclass to make the creation of a class not be done by type, but by a specified class.

In python, you can instantiate an object through a class, but in python, classes are actually objects. Since classes are objects, what is the type of a class?

class A:
    a = 1
    b = "hello"
    def f(self):
        return 12
def main():
    print(f'{type(2)=}')
    print(f'{type("hello")=}')
    print(f'{type([])=}')
    print(f'{type(A())=}')
if __name__ == "__main__":
    main()

Outputting the types of the 2, hello, empty array, and A class instances, it turns out that their classes are int, str, list, and the A class. In fact, they are also objects, since they are objects, there will be a class used to create the class.

type(2)=<class 'int'>
type("hello")=<class 'str'>
type([])=<class 'list'>
type(A())=<class '__main__.A'>

Next we'll look at these class(int,str,list) So what are the classes of these objects?

class A:
    a = 1
    b = "hello"
    def f(self):
        return 12
if __name__ == "__main__":
    print(f'{type(int)=}')
    print(f'{type(str)=}')
    print(f'{type(list)=}')
    print(f'{type(A)=}')
type(int)=<class 'type'>
type(str)=<class 'type'>
type(list)=<class 'type'>
type(A)=<class 'type'>

It's easy to see how many types of class are types, e.g., the number 2 is an instance of int, which in turn is an instance of type.

If you start with a language like java and then go to learn python, you may have the question, what is the difference between type and class in python, aren't they both types? The answer is that there is no difference between type and class in python3, they can be treated as one and the same thing.

def main():
    x = int()
    print(f'{x=}')
    B = type('B',(),{})
    print(f'{B=}')
if __name__  == "__main__":
    main()

However, if you delve further, both class and type are literally two different things. class is used as a keyword to define the type, and its constructor is called to do some initialization work.

def main():
    x = int()
    print(f'{x=}')
    B = type('B',(),{})
    print(f'{B=}')
if __name__  == "__main__":
    main()

We can define a type like this

x=0
B=<class '__main__.B'>

You can use class to define a class A, then we use type to create a class, type accepts three parameters are the name of the class, which accepts the name of the string type, as well as the base class of the class, which is in the form of a group element, and the next is an attribute, which is in the form of a dictionary, with the key being the name of the attribute, and the value being the value of the attribute.

class A:
    a = 2
    b = 'hello'

    def f(self):
        return 12

Below we use themake_A to create a class, where type is used to define a class.

def make_A():
    name = 'A'
    bases = ()
    a = 2
    b = 'hello'

    def f(self):
        return 12
    namespace = {'a':a,'b':b,'f':f}
    A = type(name,bases,namespace)
    return

To create a class by type, you need to pass in the class name A. Then base is a base class to create class A. namespace is a class attribute in the form of a dict, where the key is the name of the attribute and the value is the value of the attribute.

def make_A_more_accurate():
    name = 'A'
    bases = ()
    namespace = type.__prepare__(name,bases)
    body = (
"""
a = 1
b = 'hello'

def f(self):
    return 12
"""
    )
    exec(body,globals(),namespace)
    A = type(name,bases,namespace)
    return A

metaclass is inherited from type, so the job of metaclass is also to create classes, and we can do some custom things in metaclass.

What may be difficult to understand here is that__prepare__ Go online and find information about__prepare__ Explanation, for the moment, is a bit shallow in terms of my own understanding, which may be a bit shallow, and it feels like it creates a local scope for the class.

namespace = type.__prepare__(name,bases)
print(namespace)

type.__prepare__ should return a local namespace.

exec(body,globals(),namespace)

class Tut:
    ...
tut = Tut()
print(f'{type(tut)=}')
print(f'{type(Tut)=}')

The above example defines a class, then instantiates the Tut class to get the object tut, and then outputs the types of tut and Tut respectively.

type(tut)=<class '__main__.Tut'>
type(Tut)=<class 'type'>

It is easy to see that tut is an instance of Tut, which is an object of type

class TutMetaClass(type):
    ...
class Tut(metaclass=TutMetaClass):
    ...

Then we define a TutMetaClass inheriting from type, and then we point the metaclass of the Tut class to TutMetaClass , and then the tut type is Tut, and the Tut type is the TutMetaClass type.

type(tut)=<class '__main__.Tut'>
type(Tut)=<class '__main__.TutMetaClass'>

to this article on python metaclass metaclass details of the article is introduced to this, more related python metaclass content please search for my previous articles or continue to browse the following related articles I hope you will support me in the future more!