Python metaclass/type 原理详解
在学习 metaclass 之前先了解一下 type() 和 isinstance() 函数的用法。
内置函数 type()、isinstance()
type()
主要有两个功能:1.查看变量(对象)的类型。2.动态创建一个类 class,对你没有看错。
示例1: 当传入一个参数或者对象时,返回这个对象的类型
一般type() 函数都是用来检查对象类型的,从示例可以看出跟 object.__class__ 的功能是一致的,都是返回对象的类型
示例2: 动态创建一个类
class type(name, bases, dict)
name: 要创建的类型
bases: 要创建的类的基类, Python由于允许多继承,这里是一个元组类型
dict: 要创建类的属性,dictionary类型
上面的类是通过 Person =type('Person', (object,), dict(name='angst')) 创建了一个类 classVariable, 再通过classVariable() 创建了一个实例a。从上面的示例可以看出,两种创建的类是一致的,可以看输出结果类型都是一致的。在一般正常情况下都是通过 class XXX 来定义一个类。但是,type()也是允许动态创建类的,Python是一种解释性的动态语言
isinstance()
isinstance() 函数来判断一个对象是否是一个已知的类型,类似 type()
isinstance(object, classInfo)
object: 要判断的实例对象
classInfo: 期望的类型,可以是直接或间接类名、基本类型或者由它们组成的元组isinstance() 与 type() 区别:
type() 不会认为子类是一种父类类型,不考虑继承关系。
isinstance() 会认为子类是一种父类类型,考虑继承关系。注意:如果要判断两个类型是否相同推荐使用 isinstance()
从示例简单可以看出isinstance()与type() 的一些区别,如果想知道子类与父类之间的继承关系还可以用issubclass() 或 object.__bases__
metaclass
metaclass 元类,可以控制类的属性和类实例的创建过程。如果希望创建某一批类全部具有某种特征,则可通过 metaclass 来实现。使用 metaclass 可以在创建类时动态修改类定义。
对象、类、元类 关系图在Python 中,一切都可以是对象,整数、字符串、类实例、类本身也是对象,和其他对象一样,它是metaclass 的一个实例。
从示例的结果可以看出,默认的metaclass 是type类型的,所以我们看到Person 的类型是type,type类型?从这里可以看出有点奇怪,从开始type函数的时候,有说明过type()是可以当做函数来使用的,返回的是一个对象的类型。目前看来就有点困惑了,其实在Python中type是一个极为特殊的类型,为了彻底理解metaclass,需要先理清楚type和object的关系。
type与object 的关系
在Python3中,object 是所有类的基类,内置的类、自定义的类都是直接或者间接的继承object类,去看源码,会发现type类也是继承object类,那么问题来了?
1.首先 type 是一个metaclass ,而且是一个默认的metaclass,可以理解为type是object的类型,object又是type的一个实例。
2.type 是object 的一个子类,继承object的所有属性和行为
3.type还是一个callable对象,即实现了__call__方法,可以使用type()返回对象的类型
type 和object的关系是不可分离的,type是object的子类,同时 object又是type的一个实例(type是object的类型),type的类型也是type,看到这里我也有点费劲。但是不管它,知道是怎么回事就行了。难受
自我总结了一下:metaclass 是创建类的那个类。在python3中,我们自己定义的类,比如说Person,Animal类,它们默认的元类就是type。换句话说,Person类,Animal类也是对象,它们是type类的实例对象。因为:一切皆是对象。那么反过来可以说元类的实例就是类。
1.类由type创建,创建类时,type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)
2.对象由类创建,创建对象时,类的__init__方法自动执行,对象()执行类的 __call__ 方法
这么讲是不是就好理解多了?
下面我们来自定义一个 metaclass,自定义的metaclass 必须继承 type,自定义的metaclass 通常以Metaclass或Meta作为后缀取名来区分。
所有的累都继承自object,包括内置的类和用户自定义的类都是。一般来说,类class的类型为type(即一般的类的metaclass都是默认type,也就是type的一个实例),如果想改变类的metaclass,那么在定义类的时候,显式的指定它的metaclass即可。
在自定义metaclass的注意点:
1. object的__init__方法只有一个参数,单自定义metaclass的__init__有4个。
def __init__(self): object 只有self参数
def __init__(cls, what, bases=None, dict=None): 因为自定义的metaclass是继承type,所有必须要有4个参数。继承的super()
2.对于普通的类,重写__call__ 方法说明这个对象是callable,但在metaclass中__call__ 还负责对象的创建
下面结果代码示例看一下对象的创建过程
示例代码 测试代码结合示例来分析一个实例对象的完整创建的过程:
1.metaclass.__init: 首先进行初始化操作
2.metaclass.__call__: 创建实例,在穿件的过程中会调用class 的 __new__/__init__方法
3.class.__new__: 进行具体的实例化操作,并返回一个实例对象 at 0x000001851AC65808>
4.class.__init__: 返回一个实例对象 at 0x000001851AC65808 进行初始化
5. 返回一个用户真正需要的对象 object at 0x000001851AC65808>
从以上示例结果和对结果的分析,可以看出metaclass是如何定义一个实例对象的,以及对象在生命周期完整创建过程。
本篇学习笔记涉及的技术概念均来自《人人都懂设计模式》,有兴趣的同学可以去看看......