元类学习及示例

type和isintance

  • type()解决类或者实例是什么,不考虑继承

    type(type)
    <class 'type'>
    type(object)
    <class 'type'>
    
  • isintance考虑继承情况下的类或者实例是什么

    isinstance(type, type)
    True
    isinstance(type, object)
    True
    isinstance(object, object)
    True
    isinstance(object, type)
    True
    

元类实现单例

class Singleton(type):
    _instance = {}

    def __new__(cls, *args, **kwargs):
       # args ('AAA', (), {'__module__': '__main__', '__qualname__': 'AAA'})
       # kwargs {}
       obj = super().__new__(cls, *args, **kwargs)  # 元类实例即具体类
       print("__new__", cls)
       return obj

    def __init__(cls, *args, **kwargs):
        # args ('AAA', (), {'__module__': '__main__', '__qualname__': 'AAA'})
        # kwargs {}
        super().__init__(*args, **kwargs)
        print("__init__", cls)

    def __call__(cls, *args, **kwargs):  # cls: <class '__main__.AAA'>
        if cls not in cls._instance:
            instance = super().__call__(*args, **kwargs)  # 子类实例 instance: <__main__.AAA object at 0x0459BBD0>
            cls._instance[cls] = instance
        print("__call__")
        return cls._instance[cls]


class AAA(metaclass=Singleton):
    pass


class BBB(metaclass=Singleton):
    pass


bool(id(AAA()) == id(AAA()))  # True
bool(id(BBB()) == id(BBB()))  # True

注意点

  • 类AAA和类BBB继承元类Singleton,通过字典维护实现单例,因为字典是哈希表数据结构所以key值唯一,也可以避免并发下单例模式失效

  • 元类中__new__ _init_方法参数args值为(‘AAA’, (), {'_module_': ‘_main_’, ‘_qualname_’: ‘AAA’})。即对应

    #    类名        基类(object,) 名称空间{}
    type(class_name, class_bases, class_dict)
    
  • AAA和BBB还未实例化时,元类就已经执行了。子类实例化后再执行__call__方法

    __new__ <class '__main__.AAA'>
    __init__ <class '__main__.AAA'>
    __new__ <class '__main__.BBB'>
    __init__ <class '__main__.BBB'>
    # 子类实例化后打印日志
    __call__ <class '__main__.AAA'>
    __call__ <class '__main__.AAA'>
    __call__ <class '__main__.BBB'>
    __call__ <class '__main__.BBB'>
    

    元类执行顺序

    1. __new__返回Singleton类对象,即子类
    2. __init__初始化子类
    3. __call__子类实例化时AAA(),实际就是调用元类的call方法Singleton()()。使用super调用type的内部call方法实现
  • 元类需要继承type类,可以使用type的call等其他内置方法。具体为啥不理解,待后续补充
    个人理解:普通类创建内部实现类似于type(class_name,class_bases(父类),class_dict(类属性)。元类就像对type创建类做了一层封装,这样就可以操控类的创建过程实现一定的定制化,所以元类需要继承type

  • 注意new方法中必须传cls参数

    obj = super().__new__(cls, *args, **kwargs)
    

为什么需要元类

它允许你在运行时动态的创建类。Python 中的类也是对象,因此我们可以通过元类来定义一些通用的类方法、属性或者操作符重载,以便同时在多个类中使用。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值