MetaClass元类
一 什么是元类?
类的类(元类)就是type,其实type就是元类;
为什么要使用元类?
元类可以控制类的创建过程
type() 函数更适合于动态地创建相对简单的类,如果要创建更复杂的类,则需要通过 MetaClass(元类)的方式。
MetaClass(元类),简单的理解,就是创建类的类,即创建类之后,再由类来创建实例进行应用。
使用元类可以在创建类时动态修改类定义。
为了使用元类动态修改类定义,程序需要先定义元类。
注意,不要从字面上去理解元类的含义,事实上,MetaClass 中的 Meta 这个词根,起源于希腊语词汇 meta,包含“超越”和“改变”的意思。
定义元类时,需令其继承与 type 类,且默认的命名习惯是,让类名以 MetaClass 结尾。不仅如此,元类中需要定义并实现 __new__
() 方法(一定要有返回值)。因为元类在创建类时,该 __new__
() 方法将会被调用,用来生成新建的类。
之所有要求元类继承 type 并实现
__new__()
方法,是因为在创建类时,内部调用了 type 的__new__()
方法为这个类分配内存空间,当内存分配完成后,便会调用 type 的__init__
方法初始化
#一切皆对象
# list1 = [] #list1 = list([])
# print(type(list1)) #<class 'list'>
#自定义一个类
class Chinese(object):
country = 'china'
def __init__(self,name,age):
self.name = name
self.age = age
所有的对象都是实例化或者说调用类而得到的(调用类的过程称为类的实例化),比如对象obj是调用类Chinese得到的
obj = Chinese('leti',18,)
print(type(obj))
print(Chinese) # 类本质上也是一个对象,因为在python中 一切皆对象 ;
print(type(Chinese)) #<class 'type'>
如果一切皆为对象,那么类Chinese本质也是一个对象,既然所有的对象都是调用类得到的,那么Chinese必然也是调用了一个类得到的,这个类称为元类
于是我们可以推导出===>产生Chinese的过程一定发生了:Chinese=元类(..…)
print(type(Chinese)) #结果为<class 'type'>,证明是调用了type这个元类而产生的Chinese,即默认的元类为type
二 class关键字创建类的流程分析
上文我们基于python中一切皆为对象的概念分析出:我们用class关键字定义的类本身也是一个对象,负责产生该对象的类称之为元类(元类可以简称为类的类),内置的元类为type
class关键字在帮我们创建类时,必然帮我们调用了元类Chinese=type(..…),那调用type时传入的参数是什么呢?必然是类的关键组成部分,一个类有三大组成部分,分别是
1、类名class_name='Chinese'
2、基类们class_bases=(object,)
3、类的名称空间class_dic,类的名称空间是执行类体代码而得到的
调用type时会依次传入以上三个参数
综上,class关键字帮我们创建一个类应该细分为以下四个过程
三 自定义元类控制类
一个类没有声明自己的元类,默认他的元类就是type,除了使用内置元类type,我们也可以通过继承type来自定义元类,然后使用MetaClass关键字参数为一个类指定元类
class MyMetaClass(type): #只有继承了type类才能称之为一个元类,否则就是一个普通的自定义类
def __init__(self,class_name,class_bases,class_dict):
# print(class_name) #User
# print(class_bases) #(<class 'object'>,)
# print(class_dict) #{'__module__': '__main__', '__qualname__': 'User', 'country': 'china', '__init__': <function User.__init__ at 0x00000203F139FAF8>}
if not class_name.istitle():
raise NameError('类的首字母必须大写')
if not class_dict.get('__doc__'):
raise TypeError('必须写注释')
# 必须将类中的类名、类的基类、类的名称空间,一并返回给 type中的__init__
super().__init__(class_name,class_bases,class_dict)
class User(object,metaclass=MyMetaClass):
"""
必须写注释
"""
country = 'china'
def __init__(self,name,age):
self.name = name
self.age = age
p = User('leti','18')
自定义元类可以控制类的产生,类的产生过程其实就是元类的调用过程
即Chinese = MyMetaClass('Chinese',(object),{名称空间})
调用MyMetaClass会先产生一个空对象Chinese,然后连同调用MyMetaClass括号内的参数一同传给MyMetaClass下的__init__
方法,完成初始化