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
或者
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值