• python 中的元类


    看一个项目的源码的时候,看到了这句,class xxx(six.with_metaclass(ABCMeta, xxx)):对其中的with_metaclass不甚理解,学习一番后,原来是涉及到了python中的高级知识:元类,学习后遂作记录。

    什么是元类

    首先说,元类是创建类的类。python 中一切皆对象,那么类同样也是对象,可以说,类是其元类的实例对象。所有元类的祖宗是 type,只有 type 及其子类才能作为元类。要想看一个对象的元类,可以通过 type()obj.__class__ 查看:
    在这里插入图片描述

    如何创建类

    既然类是其元类的实例对象,那么类的创建除了写 class 关键字,还可以通过 meta(classname,(parentclass,),{attr}) 来实例化元类的方式创建。另外,如果一个类 A 由其元类 B 创建,类 C 继承类 A,那么类 C 也是由元类B创建。也就是说:某个类的元类为A,那么该类及其子类都是由元类A创建。而元类是继承 type 的,因此还可以通过 type(classname,(parentclass,),{attr}) 创建。总结以上可得,类的三种创建方法:

    1. 通过 class 关键字创建
    2. 通过 meta(classname,(parentclass,),{attr}) 创建
    3. 通过 type(classname,(parentclass,),{attr}) 创建

    其中元组()中传递的是该类继承的父类,字典 {} 传递的是类的属性或方法
    在这里插入图片描述
    以上可以看到 A,B,C 都是 class 类型。类A中通过 metaclass 指定了 MyType 是 A 的元类。

    实例的构造过程

    一个实例是怎么被类创建出来的呢?先说结论:

    类到实例经历了2个过程:

    1. 执行类的 __new__ 方法,返回一个空的对象
    2. 执行类的 __init__ 方法,对对象进行参数的初始化,后返回该对象

    因此可以说 __new__ 这个魔法方法是个构造方法,而__init__ 方法是个初始化方法。

    另外看一下 __call__ 方法,一个对象要想是可调用的,必须实现 __call__ 方法,或者说实现了__call__ 方法的对象都是可调用的。如果一个对象中实现了__call__方法,那么这个实例就可以调用。
    在这里插入图片描述

    但是要注意调用的时机。第一个 A() 只是实例化对象的操作,a() 才算是对实例的调用。
    知道了以上3个魔法方法以后,再看看类到实例经历了那些过程。
    在这里插入图片描述

    可以看到依次执行了 __new__ 方法,__init__ 方法和 __call__ 方法。其中,定义 class A 相当于实例化了 MyType,实例化A() 就相当于调用了 Mytype 实例(也就是类A),因此触发了 Mytype 的__call__方法。

    如果 __new__ 方法,__init__ 方法不返回最终得到的类就是 NoneType,可以去掉 return 重写 __new__ 方法,__init__ 方法自行验证。

    with_metaclass是什么意思

    先说结论:with_metaclass 是个函数,返回临时类,这个临时类由元类创建,同时又是新类的父类。
    这么比较难懂,看代码。
    首先看下 with_metaclass 的源码,做了些什么事情。
    with_metaclass 源码

    进一步地,代码可以简化为
    在这里插入图片描述

    以上执行 __new__ 实际就是对相应的类实例化操作。可以看到with_metaclass函数最终就是返回了 metaclass 元类的实例(也就是类),并且名字叫 temporary_class,那么 metaclass 实例化是什么呢,也就是说 metaclass 执行 __new__ 返回什么呢?因此以上代码可以继续简化为
    在这里插入图片描述

    使用 with_metaclass 创建类的代码如下
    在这里插入图片描述

    如果将A 中调用 with_metaclass 的参数带入进去就是
    在这里插入图片描述
    可以看到,其实就是使用 Mytype 元类创建了一个临时类 temporary_class,A 继承了 temporary_class,根据某个类的元类为A,那么该类及其子类都是由元类A创建,那么类A实际上也是由 Mytype 创建。这就是 with_metaclass 的作用。

    那么使用 metaclass 和 with_metaclass 有什么区别?本质上没有什么区别,只是写法上稍有不同。
    在这里插入图片描述

    元类有什么用

    通常是对定义的类有特殊要求的时候会用到,常见于框架中。
    比如要求类中的属性不能以 test 开头,就可以这样写。
    元类的作用
    最后,ABCMeta 是抽象元类,他继承 type ,如果元类不指明继承自ABCMeta,就会默认继承 type,创造的就不是抽象类了(抽象类是不能实例化的)。然后 type 是继承 object 的,object 真的是一切对象的大 boss。

    看下源码,以证以上。
    ABCMeta继承type

    type 继承 object
    type继承object
    或者
    在这里插入图片描述

  • 相关阅读:
    Rust开发——使用rust实现Redis中hset
    异步并发怎么做?
    【MATLAB编程】递归调用证明函数的极限
    [线性dp]Burenka and Traditions Codeforces1719D1&&D2
    Android通知怎么实现?Android开发如何操作相机和相册?
    【Python中is和==的区别】
    国标28181 开源WVP-PRO项目部署
    嵌入式:驱动开发 Day7
    Istio(十三):Istio项目实际案例——Online Boutique
    Linux 网络虚拟化 Macvlan(基于物理网络接口虚拟网络接口) 认知
  • 原文地址:https://blog.csdn.net/qq_26826585/article/details/126448874