zoukankan      html  css  js  c++  java
  • Python 元类

    什么是元类

    源自一句话: 在Python中, 一切皆对象, 而对象都是由类实例化得到的

     1 class OldboyTeacher:
     2     def __init__(self,name,age,sex):
     3         self.name = name
     4         self.age = age
     5         self.sex = sex
     6 
     7     def score(self):
     8         print('%s is scoring' %self.name)
     9 
    10 tea1 = OldboyTeacher('hades',18,'male')

    对象tea1是调用OldboyTeacher类得到的, 如果说一切皆对象, 那么OldboyTeacher也是一个对象,

    只要是对象都是调用一个类实例化得到的, 即OldboyTeacher=元类(....),内置的元类是type

    关系:

      1. 调用元类 ----> 自定义的类

      2. 调用自定义的类 ----> 自定义的对象

    class关键字创建自定义类的底层工作原理,分为四步:

    1. 先拿到类名: 'OldboyTeacher'

    2. 再拿到类的基类们: (object,)

    3. 然后拿到类的名称空间??? (执行类体代码, 将产生的名字放到类的名称空间也就是一个字典里,补充exec)

    3. 调用元类实例化得到自定义的类: OldboyTeacher = type('OldboyTeacher',(object,),{....})

     1 class OldboyTeacher:    # OldboyTeacher=type(...)
     2     school = 'Oldboy'
     3 
     4     def __init__(self, name, age, sex):
     5         self.name = name
     6         self.age = age
     7         self.sex = sex
     8 
     9     def score(self):
    10         print('%s is scoring' % self.name)
    11 
    12 
    13 print(OldboyTeacher)

     自定义类的三个关键组成部分:

    1. 类名

    2. 类的基类们

    3. 类的名称空间

    不依赖class关键字创建一个自定义类

    1. 拿到类名

    class_name = 'OldboyTeacher'

    2. 拿到类的基类们: (object,)

    class_bases = (object,)

    3. 拿到类的名称空间

    class_dic = {}
    
    class_body = '''
    school = 'Oldboy'
    
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    
    def score(self):
        print('%s is scoring' %self.name)
    '''
    
    exec(class_body, {}, class_dic)

    4. 调用type得到自定义的类

    OldboyTeacher = type(class_name, class_bases, class_dic)

    模板

     1 class Mymeta(type):    #但凡继承了type的类才能称之为自定义的元类,否则就只是一个普通的类
     2     def __init__(self, class_name, class_bases, class_dic):
     3         pass
     4 
     5 class OldboyTeacher(object, metaclass=Mymeta):    #OldboyTeacher=Mymeta('OldboyTeacher', (object,), {....})
     6     school = 'Oldboy'
     7 
     8     def __init__(self, name, age, sex):
     9         self.name = name
    10         self.age = age
    11         self.sex = sex
    12 
    13     def score(self):
    14         print('%s is scoring' %self.name)

    控制类的产生

    1. 类名必须用驼峰体

    2 类体必须有文档注释,且文档注释不能为空

     1 class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     2     def __init__(self, class_name, class_bases, class_dic):
     3         if class_name.islower():
     4             raise TypeError('类名必须使用驼峰体')
     5 
     6         doc = class_dic.get('__doc__')
     7         if doc is None or len(doc) == 0 or len(doc.strip('
     ')) == 0:
     8             raise TypeError('类体中必须有文档注释,且文档注释不能为空')
     9 
    10 
    11 class OldboyTeacher(object, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    12     school = 'Oldboy'
    13 
    14     def __init__(self, name, age, sex):
    15         self.name = name
    16         self.age = age
    17         self.sex = sex
    18 
    19     def score(self):
    20         print('%s is scoring' % self.name)
     1 class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     2     pass
     3 
     4 
     5 class OldboyTeacher(object):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
     6     school = 'Oldboy'
     7 
     8     def __init__(self, name, age, sex):
     9         self.name = name
    10         self.age = age
    11         self.sex = sex
    12 
    13     def score(self):
    14         print('%s is scoring' % self.name)
    15 
    16     def __call__(self, *args, **kwargs):
    17         print(self)
    18         print(args)
    19         print(kwargs)
    20 
    21 
    22 tea1 = OldboyTeacher('egon', 18, 'male')
    23 
    24 tea1(1, 2, a=1, b=2)  # __call__(tea1,(1,2).{'a':1,'b':2})

    总结: 对象之所以可以调用, 是因为对象的类中有一个函数__call__

    推导: 如果一切皆对象, 那么OldboyTeacher也是一个对象, 该对象之所可以调用, 肯定是这个对象的类中也定义了一个函数__call__

     1 class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     2     def __call__(self, *args, **kwargs):  # self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={}
     3         # 1. 先产生一个空对象
     4         tea_obj = self.__new__(self)  # tea_obj是OldboyTeacher这个类的对象
     5         # 2. 执行__init__方法,完成对象的初始属性操作
     6         self.__init__(tea_obj, *args, **kwargs)
     7         # 3. 返回初始化好的那个对象
     8         return tea_obj
     9 
    10 
    11 class OldboyTeacher(object, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    12     school = 'Oldboy'
    13 
    14     #            tea_obj,'egon',18,'male'
    15     def __init__(self, name, age, sex):
    16         self.name = name
    17         self.age = age
    18         self.sex = sex
    19 
    20     def score(self):
    21         print('%s is scoring' % self.name)
    22 
    23 
    24 tea1 = OldboyTeacher('egon', 18, 'male')  # 会触发OldboyTeacher的类(即元类)中的__call__函数

    实例化OldboyTeacher, 或者说调用OldboyTeacher:

    1. 先产生一个空对象

    2. 执行__init__方法, 完成对象的初始属性操作

    3. 返回初始化好的那个对象

    推导: 调用OldboyTeacher(...)就是在调用OldboyTeacher的类中的__call__, 那么在该__call__中就需要做上述三件事

    自定义元类来控制类的调用(即类的实例化过程)

     1 class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     2     def __call__(self, *args, **kwargs):  # self=OldboyTeacher这个类,args=('egon',18,'male'),kwargs={}
     3         # 1. 先产生一个空对象
     4         tea_obj = self.__new__(self)  # tea_obj是OldboyTeacher这个类的对象
     5         # 2. 执行__init__方法,完成对象的初始属性操作
     6         self.__init__(tea_obj, *args, **kwargs)
     7         # print(tea_obj.__dict__)
     8         tea_obj.__dict__ = {('_%s__%s' % (self.__name__, k)): v for k, v in tea_obj.__dict__.items()}
     9         # 3. 返回初始化好的那个对象
    10         return tea_obj
    11 
    12 
    13 class OldboyTeacher(object, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    14     school = 'Oldboy'
    15 
    16     def __init__(self, name, age, sex):
    17         self.name = name
    18         self.age = age
    19         self.sex = sex
    20 
    21     def score(self):
    22         print('%s is scoring' % self.name)
    23 
    24 
    25 tea1 = OldboyTeacher('egon', 18, 'male')  # 会触发OldboyTeacher的类(即元类)中的__call__函数

    属性查找

     1 class Mymeta(type):  # 但凡继承了type的类才能称之为自定义的元类,否则就是只是一个普通的类
     2     n=444
     3     def __call__(self, *args, **kwargs):  # self=OldboyTeacher这个类
     4         # 1. 先产生一个空对象
     5         tea_obj = self.__new__(self)  # tea_obj是OldboyTeacher这个类的对象
     6         # print(self.__new__ is object.__new__)
     7         # tea_obj=object.__new__(self)
     8 
     9         # 2. 执行__init__方法,完成对象的初始属性操作
    10         self.__init__(tea_obj, *args, **kwargs)
    11         # 3. 返回初始化好的那个对象
    12         return tea_obj
    13 
    14 
    15 class Bar:
    16     # n = 33
    17     pass
    18 
    19 
    20 class Foo(Bar):
    21     # n = 222
    22     pass
    23 
    24 
    25 class OldboyTeacher(Foo, metaclass=Mymeta):  # OldboyTeacher=Mymeta('OldboyTeacher',(object,),{...})
    26     # n = 111
    27     school = 'Oldboy'
    28 
    29     def __init__(self, name, age, sex):
    30         self.name = name  # None.name='egon'
    31         self.age = age
    32         self.sex = sex
    33 
    34     def score(self):
    35         print('%s is scoring' % self.name)
    36 
    37     def __new__(cls, *args, **kwargs):
    38         # print('=====>')
    39         return super().__new__(cls)
    40 
    41 
    42 tea1 = OldboyTeacher('egon', 18, 'male')
    43 print(tea1.n)
  • 相关阅读:
    51nod乘积之和
    Dell服务器安装OpenManage(OMSA)
    Nginx反向代理PHP
    搭建haproxy
    108. Convert Sorted Array to Binary Search Tree
    60. Permutation Sequence
    142. Linked List Cycle II
    129. Sum Root to Leaf Numbers
    118. Pascal's Triangle
    26. Remove Duplicates from Sorted Array
  • 原文地址:https://www.cnblogs.com/earon/p/9544709.html
Copyright © 2011-2022 走看看