概念
元类是类的类,就像类是对象的模板一样,元类是类的模板。在 Python 中,一切皆对象,类也是对象。当我们定义一个类时,Python 会在后台使用元类来创建这个类。默认情况下,Python 使用内置的type元类来创建类。
作用
可以自己定制类的某些功能,比如参数类型检查、单例模式等。然后需要使用这些功能的类指定metaclass属性,就会用元类创建类。
类创建的流程
类本质也是对象,是由元类type创建,type创建类时需要传入三个参数
- 类名 class_name
- 基类 class_bases
- 类的名称空间 class_dic
综上,class关键字帮我们创建一个类应该细分为以下四个过程:
1、拿到类名
2、拿到他的基类们;
3、执行类体代码,拿到类的名称空间;
4、调用元类返回对象(返回的对象就是我们需要的“类”) :type( class_name, class_bases, class_dict )
自定义元类
如果要自定义元类,那么只需要继承type实现类后,再在类中指定metaclass即可,如下:
class MyType(type):
def __init__(self,class_name,class_bases,class_dic):
super(Mymeta, self).__init__(class_name, class_bases, class_dic) # 重用父类的功能
if not class_name.istitle():
raise TypeError('类名%s请修改为首字母大写' %class_name)
if '__doc__' not in class_dic or len(class_dic['__doc__'].strip(' \n')) == 0:
raise TypeError('类中必须有文档注释,并且文档注释不能为空')
class Demo(object, metaclass=MyType):
pass
补充
在调用类的时候,会首先自动触发 __ new __方法,执行里面的代码,在触发_init_ 方法
class MyType(type):
def __init__(self, *args, **kwargs):
print("第2步:初始化类成员:", args, **kwargs)
super().__init__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs)
print("第1步:创建类:", new_cls)
return new_cls
class Foo(metaclass=MyType):
v1 = 123
def func(self):
pass
当实例化一个对象时,那么就需要在__call__下返回实例化对象
class MyType(type):
def __init__(cls, *args, **kwargs):
print("第2步:初始化类成员:", args, **kwargs)
super().__init__(*args, **kwargs)
def __new__(cls, *args, **kwargs):
new_cls = super().__new__(cls, *args, **kwargs)
print("第1步:创建类:", new_cls)
return new_cls
def __call__(cls, *args, **kwargs):
print("第3步:创建对象&初始化对象", cls)
# 1.调用自己那个类的 __new__ 方法去创建对象
new_object = cls.__new__(cls, *args, **kwargs)
# 2.调用你自己那个类 __init__放发去初始化
cls.__init__(new_object, *args, **kwargs)
return new_object
class Foo(metaclass=MyType):
v1 = 123
def func(self):
pass
obj = Foo()
应用
drf序列化器
ModelSerializer和Serializer都使用SerializerMetaclass作为元类来控制创建。
使用metaclass实现的优势
-
灵活性:通过自定义metaclass,可以灵活地定义类的创建过程,满足不同的序列化需求。
-
扩展性:metaclass提供了扩展基类的能力,使得开发者可以方便地添加新的功能或修改现有行为。
-
代码复用:通过继承和metaclass,可以轻松地复用已有的序列化器类,减少重复代码。