1.对python中对象的理解:
要想理解类的创建流程,首先需要理解python中对象的概念。
在python中,一切皆对象,这句话的含义可以具体化为:
1.都可以被引用
2.都可以当做函数的参数传入
3.都可以当做函数的返回值
4.都可以作为容器类的元素
2.元类的含义:
在python中创建一个类我想大家都不陌生,用class关键字就可以了:
class People:
pass # 仅做演示
类创建完毕后,我们就可以用这个类来实例化对象了:
p1 = People()
看见没,用类实例化对象其实就是在类名后面加上小括号调用类,这和函数的调用很像。
下面,我们的问题来了:既然在python中一切皆对象,那么作为类的People是不是也是一个对象呢?
答案是:是的!类People也是一个对象。
问题又来了,既然是对象,那么People也一定也需要一个类来实例化它,那这个类是什么呢?
这引出了我们这片文章的核心了:元类。
实例化出People这个类的类,就叫做元类。
在我们用class关键字定义People类的时候,其实在python解释器内部进行的操作是调用解释器默认的元类type来进行实例化:即People = type(),产生一个名叫People的对象,只不过这个对象有点特殊,它也是一个类,可以实例化对象。
当然,除了默认的元类,我们自己也可以创建元类,不过自建元类需要继承type类。
3.类对象的创建流程
为了理解类对象的创建流程,我们先看下面的一段代码:
print('创建我的元类:')
class MyMetaclass(type): # 自建我们的自己的元类
def __init__(self,name,bases,dict):
print('init')
super().__init__(name,bases,dict)
def __call__(self, *args, **kwargs):
print('call')
return super().__call__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
print('new')
return super().__new__(cls, *args, **kwargs)
pass
print('创建People类:')
class People(object,metaclass=MyMetaclass): # 以MyMetaclass为元类创建一个类
def __init__(self):
print('sub_init')
super().__init__()
def __call__(self, *args, **kwargs):
print('sub_call')
def __new__(cls, *args, **kwargs):
print('sub_new')
return super().__new__(cls, *args, **kwargs)
他的输出结果是:
创建我的元类:
创建People类:
new
init
如上,我们可以知道,在创建类的时候,python解释器内部依次调用了元类内的__new__和__init__方法,通过查找资料可以知道:
1.__new__方法其实继承于python中默认基类object类,他的作用时新建一个空的对象=obj(这里我们为了便于叙述将其命名为obj),然后将obj传入__init__方法初始化,即obj.属性=你传入__init__的其他参数
2.需要注意的是,在如果一个类实例化的对象是类,__init__函数需要传入4个参数:self(这里就是__new__方法创建的空对象),classname(你想要创建的类的名字,用上面的例子来说就是People),classbases(你想要创建的类的基类,默认是object),classdict(你想要创建的类的名称空间,里面以字典形式保存了类的数据属性)
但是还没有结束,我们将上面的例子再扩展一下:
print('创建我的元类:')
class MyMetaclass(type):
def __init__(self,name,bases,dict):
print('init')
super().__init__(name,bases,dict)
def __call__(self, *args, **kwargs):
print('call')
return super().__call__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
print('new')
return super().__new__(cls, *args, **kwargs)
pass
print('创建People类:')
class People(object,metaclass=MyMetaclass):
def __init__(self):
print('sub_init')
super().__init__()
def __call__(self, *args, **kwargs):
print('sub_call')
def __new__(cls, *args, **kwargs):
print('sub_new')
return super().__new__(cls, *args, **kwargs)
print('p1实例化后:')
p1 = People()
print('调用p1:')
p1()
它的输出结果是:
创建我的元类:
创建People类:
new
init
p1实例化后:
call
sub_new
sub_init
调用p1:
sub_call
从上面的结果可以看出,People类在实例化对象p1的时候, 会先调用元类MyMetaclass的__call__函数,然后再调用People类自己的__new__和__init__方法,而且后面调用p1的时候,也调用了People的__call__方法。
可见之前我们认为实例化对象的时候只调用类自己的__new__和__init__方法的结论并不完善。
结合上面的代码实验,我们可以基本看出python实例化对象的流程:
1.创建普通对象:在python中,调用一个类去实例化对象的时候,会先调用这个类的元类的__call__方法,在元类的__call__方法中,会先调用类自己的__new__方法创建空对象,然后用类自己的__init__方法初始化这个空对象,最后元类的__call__的方法将初始化后的对象返回,作为实例化结果赋值给你想赋值的对象。
2.创建类对象(类的创建流程):基本流程同第一点,需要注意的是:当调用的对象是元类的时候(即你想生成一个类),在用__init__函数初始化的时候,空对象作为__init__函数的第一个参数传入,【你想要创建的类的名字,你想要创建的类的基类,你想要创建的类的名称空间】作为必须的后三个参数传入__init__函数,最后元类的__call__的方法将初始化后的对象返回,即你创建了一个类。