两句话掌握 Python 最难知识点——元类出处( 二 )

  • type可以直接生成类(class),但也可以先生成元类(metaclass),再使用元类批量定制类(class) 。
  • 元类——道生一,一生二一般来说,元类均被命名后缀为Metalass 。想象一下,我们需要一个可以自动打招呼的元类,它里面的类方法呢,有时需要say_Hello,有时需要say_Hi,有时又需要say_Sayolala,有时需要say_Nihao 。
    如果每个内置的say_xxx都需要在类里面声明一次,那将是多么可怕的苦役! 不如使用元类来解决问题 。
    以下是创建一个专门“打招呼”用的元类代码:
    Python
    1
    2
    3
    4
    5
    class SayMetaClass(type):
    def __new__(cls, name, bases, attrs):
    attrs['say_'+name] = lambda self,value,saying=name: print(saying+','+value+'!')
    return type.__new__(cls, name, bases, attrs)
    记住两点:
    1、元类是由“type”衍生而出,所以父类需要传入type 。【道生一,所以一必须包含道】
    2、元类的操作都在 __new__中完成,它的第一个参数是将创建的类,之后的参数即是三大永恒命题:我是谁,我从哪里来,我将到哪里去 。它返回的对象也是三大永恒命题,接下来,这三个参数将一直陪伴我们 。
    在__new__中,我只进行了一个操作,就是
    Python
    1
    attrs['say_'+name] = lambda self,value,saying=name: print(saying+','+value+'!')
    它跟据类的名字,创建了一个类方法 。比如我们由元类创建的类叫“Hello”,那创建时就自动有了一个叫“say_Hello”的类方法,然后又将类的名字“Hello”作为默认参数saying,传到了方法里面 。然后把hello方法调用时的传参作为value传进去,最终打印出来 。
    那么,一个元类是怎么从创建到调用的呢?
    来!一起根据道生一、一生二、二生三、三生万物的准则,走进元类的生命周期吧
    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 道生一:传入type
    class SayMetaClass(type):
    # 传入三大永恒命题:类名称、父类、属性
    def __new__(cls, name, bases, attrs):
    # 创造“天赋”
    attrs['say_'+name] = lambda self,value,saying=name: print(saying+','+value+'!')
    # 传承三大永恒命题:类名称、父类、属性
    return type.__new__(cls, name, bases, attrs)
    # 一生二:创建类
    class Hello(object, metaclass=SayMetaClass):
    pass
    # 二生三:创建实列
    hello = Hello()
    # 三生万物:调用实例方法
    hello.say_Hello('world!')
    输出为
    1
    Hello, world!
    注意:通过元类创建的类,第一个参数是父类,第二个参数是metaclass
    普通人出生都不会说话,但有的人出生就会打招呼说“Hello”,“你好”,“sayolala”,这就是天赋的力量 。它会给我们面向对象的编程省下无数的麻烦 。
    现在,保持元类不变,我们还可以继续创建Sayolala,Nihao类,如下:
    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 一生二:创建类
    class Sayolala(object, metaclass=SayMetaClass):
    pass
    # 二生三:创建实列
    s = Sayolala()
    # 三生万物:调用实例方法
    s.say_Sayolala('japan!')
    输出
    Python
    1
    Sayolala, japan!
    也可以说中文
    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 一生二:创建类
    class Nihao(object, metaclass=SayMetaClass):
    pass
    # 二生三:创建实列
    n = Nihao()
    # 三生万物:调用实例方法
    n.say_Nihao('中华!')
    输出
    Python
    1
    Nihao, 中华!
    再来一个小例子:
    Python
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    # 道生一
    class ListMetaclass(type):
    def __new__(cls, name, bases, attrs):
    # 天赋:通过add方法将值绑定
    attrs['add'] = lambda self, value: self.Append(value)
    return type.__new__(cls, name, bases, attrs)
    # 一生二


    推荐阅读