python3-metaclass的使用

1、简介:

metaclass翻译为元类,字面理解“元”是本源,它可以控制类的创建行为。

定义上很难理解它的意思,现在开始举例子说明它的用法。

2、原理:

  1. python中用户自定义的类,实际上是type这个类的实例,接下来用代码说明:

    class MyClass(object):
        pass
    instance = MyClass()
    print(type(instance))
    print(type(MyClass))
    # 输出
    <class '__main__.MyClass'>
    <class 'type'>

    可以看到,instanceMyClass的实例,而MyClasstype的实例。

  2. 用户创建类实例时,其实是调用了type__call__方法。

    创建这样一个类:

    class MyClass:
        data = 1

    实际上执行的是下面这段代码:

    MyClass = type('MyClass', (), {'data': 1})

    看下实际的执行:

    class MyClass:
        data = 1
    instance = MyClass()
    print(instance)
    # 输出
    <__main__.MyClass object at 0x000002710DB8D608>
    ​
    MyClass = type('MyClass', (), {'data': 1})
    instance = MyClass()
    print(instance)
    # 输出
    <__main__.MyClass object at 0x000002710DB8D608>

     

  3. metaclass(此处为自己定义的元类)是type的子类,可以通过重载type__call__方法,来控制类的创建,使其不再是普通的类。

    MyClass = type('MyClass', (), {'data': 1})

    就变成了(MyMeta需要自己定义,必须是type的子类):

    MyClass = MyMeta('MyClass', (), {'data': 1})

     

  4. 举个例子:

    class MyMeta(type):
        def __new__(cls, *args, **kwargs):
            print("MyMeta------__new__")
         return type.__new__(cls, *args, **kwargs)
    ​
        def __init__(cls, name, bases, dic):
            print("MyMeta------__init__")
            super().__init__(name, bases, dic)
    ​
        def __call__(cls, *args, **kwargs):
            print("MyMeta------__call__")
            return type.__call__(cls, *args, **kwargs)
        
    class MyClass(metaclass=MyMeta):
        data = 1
        
    instance = MyClass()
    # 打印
    MyMeta------__new__
    MyMeta------__init__
    MyMeta------__call__

    可以看到,创建类的时候,就会自动执行对应元类的__new____init__,创建对应类实例时,就会执行对应的__call__

3、实际应用:

  1. 设计模式--单例模式:

    class Single_instance(type):
        def __init__(self, name, bases, dic):
            self.__instance = None
            super().__init__(name, bases, dic)
    ​
        def __call__(self, *args, **kwargs):
            if not self.__instance:
                self.__instance = super().__call__(*args, **kwargs)
            return self.__instance
    ​
    class MyClass(metaclass=Single_instance):
        pass
    ​
    c1 = MyClass()
    c2 = MyClass()
    print(c1)
    print(c2)
    # 打印
    <__main__.MyClass object at 0x0000016856510EC8>
    <__main__.MyClass object at 0x0000016856510EC8>

     

  2. import yaml
    
    class People(yaml.YAMLObject):
      yaml_tag = u'!Monster'
      def __init__(self, name, age, sex):
        self.name = name
        self.age = age
        self.sex = sex
      def __repr__(self):
        return f"{self.__class__.__name__}(name={self.name}, age={self.age}, sex={self.sex})"
    
    p1 = yaml.full_load("""
    !Monster
    name: ZhangSan
    age: 16
    sex: boy
    """)
    print(type(p1))
    print(p1)
    # 打印
    <class '__main__.People'>
    People(name=ZhangSan, age=16, sex=boy)
    
    p2 = People("LiSi", 14, "boy")
    print(p2)
    print(yaml.dump(p2))
    # 打印
    People(name=LiSi, age=14, sex=boy)
    !Monster
    age: 14
    name: LiSi
    sex: boy

    YAMLObject便是使用YAMLObjectMetaclass(自定义元类)创建的类,该功能称为序列化/反序列化,调用yaml.yaml.full_load()就能把一个yaml格式的内容加载成一个object,而yaml.dump()就能把一个YAMLObject子类序列化。

    这样在只需要修改yaml的配置文件,就可以动态修改想要创建的实例。

4、总结:

metaclass的功能很强大,可以修改类的创建过程,实现单例、缓存以及上面的序列化/反序列化等的功能,同样如果使用不慎,会出现很大的问题。

官方使用说明:https://github.com/yidao620c/python3-cookbook/blob/master/source/c09/p13_using_mataclass_to_control_instance_creation.rst

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值