Metaclass (the metaclass that)

114- yuan class metaclass- warning .jpg

introduction

  • Yuan class deep magic belongs to object-oriented programming python, 99% of people miss the point, those who think they do understand metaclasses people are actually only be justified, go beyond that, from the control of the yuan would like to see one hundred flaws, logic confusion, today I come to take you to understand the depth of python metaclass context.

  • Behind the author in simple terms is a technology obsession, day after day, hoping that we can respect the original, to the text and therefore we can solve all the doubts and meta-class and feel happy! ! !

What is the metaclass

  • Everything in python object, we use the class keyword to define the class itself is an object, the object's class is responsible for generating called metaclass that may be referred to as meta-class class class
class Foo:  # Foo=元类()
    pass

Creating .png 114- metaclass metaclass- class

Why metaclass

  • Yuan class is responsible for generating the class, so we have to learn or a custom metaclass metaclass purpose: to control the production process and the like, you can also control the production process objects

Built-in functions exec (reserve)

cmd = """
x=1
print('exec函数运行了')
def func(self):
    pass
"""
class_dic = {}
# 执行cmd中的代码,然后把产生的名字丢入class_dic字典中
exec(cmd, {}, class_dic)
exec函数运行了
print(class_dic)
{'x': 1, 'func': <function func at 0x10a0bc048>}

class create class

  • If the class is also an object, then use the process to create the class keyword class is also an instance of the process, the instance of the class in order to get a call that metaclass

  • Create a class with the class keyword, use the default metaclass type, and therefore before the judge not to see as the category type

class People:  # People=type(...)
    country = 'China'

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

    def eat(self):
        print('%s is eating' % self.name)
print(type(People))
<class 'type'>

114- metaclass metaclass-class keyword .png

type realization

  • Namespace class name, base class, class: create a class of three elements

  • People = type (class name, base class, the class namespace)

class_name = 'People'  # 类名

class_bases = (object, )  # 基类

# 类的名称空间
class_dic = {}
class_body = """
country='China'
def __init__(self,name,age):
    self.name=name
    self.age=age
def eat(self):
    print('%s is eating' %self.name)
"""

exec(
    class_body,
    {},
    class_dic,
)
print(class_name)
People
print(class_bases)
(<class 'object'>,)
print(class_dic)  # 类的名称空间
{'country': 'China', '__init__': <function __init__ at 0x10a0bc048>, 'eat': <function eat at 0x10a0bcd08>}
  • People = type (class name, base class, the class namespace)
People1 = type(class_name, class_bases, class_dic)
print(People1)
<class '__main__.People'>
obj1 = People1(1, 2)
obj1.eat()
1 is eating
  • Call the class to create the class
print(People)
<class '__main__.People'>
obj = People1(1, 2)
obj.eat()
1 is eating

114- yuan class metaclass- slowly .jpg

Create a custom control class metaclass

  • Using a custom metaclass
class Mymeta(type):  # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    def __init__(self, class_name, class_bases, class_dic):
        print('self:', self)  # 现在是People
        print('class_name:', class_name)
        print('class_bases:', class_bases)
        print('class_dic:', class_dic)
        super(Mymeta, self).__init__(class_name, class_bases,
                                     class_dic)  # 重用父类type的功能
  • Analysis of the operating principle of self-defined class (rather than the operating principle of the meta-class) with the class:

    1. To get a string format class name class_name = 'People'

    2. To get a base class are class_bases = (obejct,)

    3. Class body execution code of the class to get a namespace class_dic = {...}

    4. 调用People=type(class_name,class_bases,class_dic)

class People(object, metaclass=Mymeta):  # People=Mymeta(类名,基类们,类的名称空间)
    country = 'China'

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

    def eat(self):
        print('%s is eating' % self.name)
self: <class '__main__.People'>
class_name: People
class_bases: (<class 'object'>,)
class_dic: {'__module__': '__main__', '__qualname__': 'People', 'country': 'China', '__init__': <function People.__init__ at 0x10a0bcbf8>, 'eat': <function People.eat at 0x10a0bc2f0>}

application

  • Custom metaclass generation process control class, the class is actually generating process called procedure yuan class

  • We can control the class must have a document, you can use the following means to achieve

class Mymeta(type):  # 只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
    def __init__(self, class_name, class_bases, class_dic):
        if class_dic.get('__doc__') is None or len(
                class_dic.get('__doc__').strip()) == 0:
            raise TypeError('类中必须有文档注释,并且文档注释不能为空')
        if not class_name.istitle():
            raise TypeError('类名首字母必须大写')
        super(Mymeta, self).__init__(class_name, class_bases,
                                     class_dic)  # 重用父类的功能
try:

    class People(object, metaclass=Mymeta
                 ):  #People  = Mymeta('People',(object,),{....})
        #     """这是People类"""
        country = 'China'

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

        def eat(self):
            print('%s is eating' % self.name)
except Exception as e:
    print(e)
类中必须有文档注释,并且文档注释不能为空

__call __ (reserve)

  • To get the object obj become a target of a call, you need to define a method in the object's class ,, __ call__ method, which is automatically triggered when the calling object
class Foo:
    def __call__(self, *args, **kwargs):
        print(args)
        print(kwargs)
        print('__call__实现了,实例化对象可以加括号调用了')


obj = Foo()
obj('nick', age=18)
('nick',)
{'age': 18}
__call__实现了,实例化对象可以加括号调用了

Examples of custom control class metaclass

class Mymeta(type):
    def __call__(self, *args, **kwargs):
        print(self)  # self是People
        print(args)  # args = ('nick',)
        print(kwargs)  # kwargs = {'age':18}
        # return 123
        # 1. 先造出一个People的空对象,申请内存空间
        obj = self.__new__(self)
        # 2. 为该对空对象初始化独有的属性
        self.__init__(obj, *args, **kwargs)
        # 3. 返回一个初始化好的对象
        return obj
  • People = Mymeta (), People () will trigger __call__
class People(object, metaclass=Mymeta):
    country = 'China'

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

    def eat(self):
        print('%s is eating' % self.name)


#     在调用Mymeta的__call__的时候,首先会找自己(如下函数)的,自己的没有才会找父类的
#     def __new__(cls, *args, **kwargs):
#         # print(cls)  # cls是People
#         # cls.__new__(cls) # 错误,无限死循环
#         obj = super(People, cls).__new__(cls)
#         return obj
  • Class is called, i.e. the calling procedure is the class instantiation metaclass can be controlled by the __call__ metaclass Mymeta

  • Analysis: The purpose of the call Pepole

    1. First create a null object of People

    2. For empty object initialization unique properties

    3. Returns a good object initialization

obj = People('nick', age=18)
<class '__main__.People'>
('nick',)
{'age': 18}
print(obj.__dict__)
{'name': 'nick', 'age': 18}

114- metaclasses inherit .jpg metaclass-

Custom order of succession after class metaclass

class Mymeta(type):
    n = 444


#     def __call__(self, *args, **kwargs):
#         obj = self.__new__(self)  # self = Foo
#         # obj = object.__new__(self)  # self = Foo
#         self.__init__(obj, *args, **kwargs)
#         return obj


class A(object):
    #     n = 333
    pass


class B(A):
    #     n = 222
    pass


class Foo(B, metaclass=Mymeta):  # Foo = Mymeta(...)
    #     n = 111

    def __init__(self, x, y):
        self.x = x
        self.y = y


for i in Foo.mro():
    print(i)
<class '__main__.Foo'>
<class '__main__.B'>
<class '__main__.A'>
<class 'object'>
print(Foo.n)
444
  • Find the order:

    1. First object layer: Foo-> B-> A-> object

    2. Then metaclass Layer: Mymeta-> type

print(type(object))
<class 'type'>
obj = Foo(1, 2)
print(obj.__dict__)
{'x': 1, 'y': 2}

114- yuan class metaclass- exam .jpg

Use metaclass modify the properties remain hidden

class Mymeta(type):
    def __init__(self, class_name, class_bases, class_dic):
        # 加上逻辑,控制类Foo的创建
        super(Mymeta, self).__init__(class_name, class_bases, class_dic)

    def __call__(self, *args, **kwargs):
        # 加上逻辑,控制Foo的调用过程,即Foo对象的产生过程
        obj = self.__new__(self)
        self.__init__(obj, *args, **kwargs)
        # 修改属性为隐藏属性
        obj.__dict__ = {
            '_%s__%s' % (self.__name__, k): v
            for k, v in obj.__dict__.items()
        }

        return obj
class Foo(object, metaclass=Mymeta):  # Foo = Mymeta(...)
    def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex


obj = Foo('egon', 18, 'male')
print(obj.__dict__)
{'_Foo__name': 'egon', '_Foo__age': 18, '_Foo__sex': 'male'}

Guess you like

Origin www.cnblogs.com/nickchen121/p/10992975.html