Python元类深度解析
目录
一、创建类的方式
二、元类的概念
三、元类创建类的步骤
四、python元类机制的底层实现
五、元类的继承关系
最近学习到了元类,在此记录其相关概念与应用,希望能够帮到对此有疑惑的人。
一、创建类的方式
在python中我们创建类最常见的方式就是:
class Bug(object):
v1 = 123
def test(self):
print("这是一个测试")
b = Bug()
print(b.v1)
b.test()
我们运行上面的代码就会打印出:

但其实还有一种创造类的方法:
类名=type('类名',(父类,),{成员,})
就像下面的代码:
Bug = type("Bug", (object,), {"v1":123,"test":lambda x:print("这是一个测试")})
b = Bug()
print(b.v1)
b.test()
这里我同样创建了一个类名叫"Bug",其中有成员v1和test,运行上面的代码同样可以得到下面的结果:

为什么会有这种type方法来创建类呢?其实这种type就是我接下来要说的元类。
二、元类的概念
元类(metaclass)用来创建python中的'类',而上面我们所使用的type就是python中默认的元类,也就是说,我们创建类时,其实代码是这样的:
class Bug(object, metaclass=type)两种创建类的方法本质上都是用type创建的。我们可以通过查看type的代码,看出type本质上就是一个类:(这里只截取了一小段源代码)
class type(object): """ type(object) -> the object's type type(name, bases, dict, **kwds) -> a new type """ def __call__(self, *args, **kwargs): # real signature unknown """ Call self as a function. """ pass def __init__(cls, what, bases=None, dict=None): # known special case of type.__init__ """ type(object) -> the object's type type(name, bases, dict, **kwds) -> a new type # (copied from class doc) """ pass @staticmethod # known case of __new__ def __new__(*args, **kwargs): # real signature unknown """ Create and return a new object. See help(type) for accurate signature. """ pass
三、元类创建类的步骤
既然type也是一个类,那么我们就可以知道,当我们使用类名=type('类名',(父类,),{成员,})这种方法创建类时,会先执行__new__方法创建一个空类,然后再调用__init__方法往空值中写数据。我们可以通过自定义的type类来查看这一先后步骤。
class MyType(type):
def __new__(cls, name, bases, attrs):
print("先创建一个空类")
xx = super().__new__(cls,name,bases,attrs)
return xx
def __init__(cls, name, bases, attrs):
print("往空类中注入数据")
super().__init__(name,bases,attrs)
class Bug(object, metaclass=MyType):
v1 = 123
def test(self):
print("这是一个测试")
# Bug = type("Bug", (object,), {"v1":123,"test":lambda x:print("这是一个测试")})
b = Bug()
print(b.v1)
b.test()
执行上面的代码,我们会得到如下的结果:

而当我们在实例化一个类时比如b=Bug(),解释器会调用__call__方法来先执行__new__,再执行__init__,我们用代码来展示这一过程:
class MyType(type):
def __call__(cls, *args, **kwargs):
print("执行call方法")
obj = super().__call__(*args, **kwargs)
return obj
def __new__(cls, name, bases, attrs):
print("先创建一个空类")
xx = super().__new__(cls,name,bases,attrs)
return xx
def __init__(cls, name, bases, attrs):
print("往空类中注入数据")
super().__init__(name,bases,attrs)
class Bug(object, metaclass=MyType):
v1 = 123
def __init__(self):
print("初始化")
def __new__(cls, *args, **kwargs):
print("实例化类的对象")
return super().__new__(cls)
def test(self):
print("这是一个测试")
b = Bug()
print(b.v1)
b.test()
结果如下:

我们可以看到,当我们的代码运行到b=Bug()时,会执行__call__方法,先后运行了__new__,__init__。
通过打印出来的结果,我们会发现,在”执行call方法“这一结果上面还有两个打印结果,它并没有执行call方法,而是直接执行了new和init方法。
这涉及到Python 元类机制的底层实现细节。
四、python元类机制的底层实现
在之前我们运行代码时,出现了在”执行call方法“这一结果上面还有两个打印结果,它并没有执行call方法,而是直接执行了new和init方法 这一现象,这是为什么呢?
这是因为,当我们创建类时,python不会调用__call__方法,而是直接使用__new__,__init__方法创建类。
当我们写
class Bug(object, metaclass=MyType):
...
时,这段代码实际会执行:
Bug = MyType("Bug", (object,), {...})
python底层会自动调用元类MyType来创建这个类,会用到MyType.__new__ 和 MyType.__init__。
他会直接绕过__call__方法,来创建这个类,因为python在创建类时,是需要严格控制其过程的,不能被用户随意篡改,所以他就直接绕过了__call__方法,直接在内部近似执行:
Bug = MyType.__new__(MyType, "Bug", (object,), {...})
MyType.__init__(Bug, "Bug", (object,), {...})
所以在创建类时,不会执行__call__方法
五、元类的继承关系
当父类指定了metaclass,子类会全部由父类指定的metaclass创建。
代码实现:
class MyType(type): def __call__(cls, *args, **kwargs): print("执行call方法") obj = super().__call__(*args, **kwargs) return obj def __new__(cls, name, bases, attrs): print("先创建一个空类") xx = super().__new__(cls,name,bases,attrs) return xx def __init__(cls, name, bases, attrs): print("往空类中注入数据") super().__init__(name,bases,attrs) class Bug(object, metaclass=MyType): v1 = 123 def test(self): print("这是一个测试") class s(Bug): v2 = 1245 S = s() print(S.v2)运行结果:
作者:どうした60
