元类
元类
元类的介绍
元类就是用来实例化类的类,即元类的实例化为类,类的实例化为对象。
我们都知道对象是怎么产生的 ,
class People:
def __init__(self,name,age):
self.name = name
self.age =age
# 类的实例化产生对象
p1 = People("tom",14)
print(type(People)) # <class "type"> 说明People类是由type元类实例化的类。
类的实例化是通过调用类名()的方式实例化对象。那么元类是不是也是通过这种方式来实例化类呢?
通过打印type(People)
可以看出People类是由type元类实例化的类。当类不注明其继承的元类时,一般都默认继承type元类。
如何自定义产生类
类一共有三大特征:类名、类的基类、执行类体代码的名称空间。通过这三个特征,我们 可以造出来一个类。
# 类的名字
class_name = "People"
# 类的基类
class_bases = (object)
# 执行类体代码拿到的名称空间
class_dic = {}
class_body = '''
def __init__(self,name,age):
self.name = name
self.age = age
'''
exec(class_body,{},class_dic)
# 调用type元类,将三个参数传入,实例化产生类。
People= type(class_name,class_bases,class_dic)
exec(“字符串形式的代码”,{字典形式的全局作用域},{局部作用域})。当执行这一方法的时候,首先会执行字符串形式的代码,将在其内部产生的局部名称空间内部。
上述代码就实现了自定义类的创建,这就是class关键字执行的步骤。
如何自定义产生元类
通常情况下,创建类没有声明自己的元类,那么默认其元类为type。我们还可以自定义元类来创建类。这时,我们都是使用metclass关键字来自定义元类。当然,所有的元类都必须继承type,只有继承了type,才能被称为元类。
class Mymeta(type): # 只有继承了type 才能被称为元类。
pass
class People(object,metaclass=Mymeta): # 一般情况默认metaclass = "type"
def __init__(self,name,age):
self.name = name
self.age = age
之前我们说过,元类实例化产生类,那么我们实例化People类的过程实际就是调用Mymeta元类的过程,然后将class_name,class_bases,class_dic当作参数传入_init_。最后产生了类
- 在调用Mymeta元类的时候首先会产生一个类的空对象。
- 初始化对象。
- 返回初始化好的对象。
按照上述过程,可以总结为
- 首先执行了Mymeta元类的__new__方法,产生类的空对象。
- 其次执行了__init__方法初始化了类对象。
- return了一个初始化之后的类对象。
class Mymeta(type):
def __init__(self,class_name,class_bases,class_dic):
super().__init__(class_name,class_bases,class_dic)
def __new__(cls,*args,**kwargs):
return super().__new__(cls,*args,**kwargs)
People = Mymeta(class_name,class_bases,class_dic)
class People(object,metaclass=Mymeta): # 一般情况默认metaclass = "type"
def __init__(self,name,age):
self.name = name
self.age = age
因此,只要是调用类的时候,都会调用类的_new__和__init_。
为什么对象不能通过加括号的方式调用呢?因为对象内没有__call__的内置方法。既然元类可以加括号来调用,那么就说明其一定有一个__call__在被调用的时候就自动执行了,那么其返回值也就是该内置方法的返回值。
那么就是说调用__init__
和__new__
肯定是发生在__call__
内部的。