元类
1、元类(Metaclass)的概念
- 元类是Python中一个高级概念,本质上是**“类的类”**,用于控制创建类的过程。元类是创建类的模板
- 在Python中:
- 类定义了实例的行为
- 元类定义了类的行为
2、python中的默认元类
-
在Python中,type是所有类的默认元类。
-
我们所熟知的object基类就是type元类的一个实例
-
当使用class关键字创建类时,因为没有指定元类,因此python会寻找父类的元类,如果父类也没有元类的话会退回到最初的type类。
-
找到元类后,基于元类创建类其实就是执行了元类中的
__new__
和__init__
方法来创建一个类
class MyClass:pass # 等价于 MyClass = type('MyClass', (), {})
使用上述代码创建一个类,实际上是以下代码的语法糖:
MyClass = type('MyClass', (), {})
3、创建元类的过程
- 因为创建类其实就是执行元类中的
__new__
、__init__
方法,因此要创建自己的元类需要继承type类并通常覆盖__new__
或__init__
方法- new: 创建类对象
- init: 初始化类对象
- prepare: 返回用于类属性初始化的名称空间字典
class MyMeta(type):@classmethoddef __prepare__(cls, name, bases, **kwargs):"""在类创建前准备命名空间返回一个用于存储类属性的字典-like对象"""print(f"1. __prepare__: 准备 {name} 的命名空间")# 这里使用普通字典,但可以返回自定义的字典子类# 例如 OrderedDict 保持属性顺序return {'__annotations__': {}}def __new__(mcls, name, bases, namespace, **kwargs):"""实际创建类对象可以修改类的属性或基类"""print(f"2. __new__: 创建 {name} 类对象")# 自动添加类创建时间戳namespace['created_at'] = '2023-11-01'# 强制添加前缀到非魔术方法属性名new_namespace = {f'custom_{k}' if not k.startswith('__') else k: vfor k, v in namespace.items()}return super().__new__(mcls, name, bases, new_namespace)def __init__(cls, name, bases, namespace, **kwargs):"""初始化已创建的类可以添加类初始化逻辑"""print(f"3. __init__: 初始化 {name} 类")super().__init__(name, bases, namespace)# 添加类方法cls.class_info = lambda self: f"Class {name} created with MyMeta"
4、使用元类
使用metaclass
参数指定要继承的元类:
class MyClass(metaclass=MyMeta):"""使用自定义元类的示例类"""value = 42def __init__(self, x):self.x = xdef method(self):return self.x# 测试输出
print("\n类创建完成,开始实例化测试:")
obj = MyClass(10)
print(f"访问修改后的属性: value -> {hasattr(MyClass, 'value')}") # False
print(f"访问添加的前缀属性: custom_value -> {MyClass.custom_value}") # 42
print(f"访问自动添加的属性: created_at -> {MyClass.created_at}") # 2023-11-01
print(f"调用添加的方法: {obj.class_info()}") # Class MyClass created with MyMeta
5、元类的主要用途
- 控制类的创建行为:可以在类创建时修改类属性
- 自动注册子类:框架中自动发现和注册插件
- 强制接口实现:确保子类实现了特定方法
ORM实现:如Django的Model、SQLAlchemy的DeclarativeBase
6、元类的实际应用
- 注册所有子类
class PluginMeta(type):def __init__(cls, name, bases, namespace):super().__init__(name, bases, namespace)if not hasattr(cls, 'plugins'):cls.plugins = []else:cls.plugins.append(cls)class Plugin(metaclass=PluginMeta):passclass PluginA(Plugin):passclass PluginB(Plugin):passprint(Plugin.plugins) # 输出: [<class '__main__.PluginA'>, <class '__main__.PluginB'>]
- 强制方法实现
class AbstractMeta(type):def __new__(cls, name, bases, namespace):if 'required_method' not in namespace:raise TypeError(f"{name} must implement 'required_method'")return super().__new__(cls, name, bases, namespace)class AbstractClass(metaclass=AbstractMeta):passclass ValidClass(AbstractClass):def required_method(self):passclass InvalidClass(AbstractClass): # 会引发TypeErrorpass
- 自动添加属性
class AutoAttributeMeta(type):def __new__(cls, name, bases, namespace):namespace['auto_attr'] = f"auto_{name.lower()}"return super().__new__(cls, name, bases, namespace)class MyClass(metaclass=AutoAttributeMeta):passprint(MyClass.auto_attr) # 输出: auto_myclass
动态类
1、什么是动态类
- 动态类是指在程序运行时(而非编写代码时)动态创建的类。
- 动态类具备根据需要修改类的结构和行为的灵活性
- 动态类的元编程能力利用了python的反射和元类机制
2、使用type()函数动态创建类
type
的三个参数:- 类名
- 基类元组
- 包含属性的字典
- 动态创建类的基本方法: type(类名, 基类元组, 属性字典)
DynamicClass = type('DynamicClass', (), {'x': 10,'say_hello': lambda self: f"Hello! x is {self.x}"
})
# 这个类的创建等价于:
# class DynamicClass: 静态定义
# 'x': 10,
# 'say_hello': lambda self: f"Hello! x is {self.x}"obj = DynamicClass()
print(obj.say_hello()) # 输出: Hello! x is 10
- 在类定义后,为类动态添加属性和方法
class Person:pass# 动态添加方法
def greet(self):return f"Hello, I'm {self.name}"Person.greet1 = greetp = Person()
p.name = "Alice"
print(p.greet1()) # 输出: Hello, I'm Alice
p.__dict__ # 输出:{'name': 'Alice'},表示这个实例只有name属性
- 使用 types.new_class() 创建(Python 3.3+)
from types import new_classdef __init__(self, value):self.value = valueDynamicClass = new_class('DynamicClass',(object,),exec_body=lambda ns: ns.update({'__init__': __init__,'get_value': lambda self: self.value})
)obj = DynamicClass(42)
print(obj.get_value()) # 输出: 42
3、动态类的优势
- (1) 运行时决定类结构
def create_class(has_method):attrs = {'x': 10}if has_method:attrs['method'] = lambda self: "Dynamic!"return type('DynamicClass', (), attrs)ClassWithMethod = create_class(True)
ClassWithoutMethod = create_class(False)
- (2) 动态继承
BaseClass = SomeClass if condition else AnotherClass
DynamicClass = type('DynamicClass', (BaseClass,), {})
- (3) 与元编程结合
class Meta(type):def __new__(cls, name, bases, attrs):attrs['custom'] = "Added by metaclass"return super().__new__(cls, name, bases, attrs)# 动态使用元类
DynamicClass = type('DynamicClass', (), {'__metaclass__': Meta})
4、动态类的实际应用场景
-
插件系统:运行时加载和注册插件类
-
ORM 映射:根据数据库表结构动态生成模型类
-
协议适配:根据不同的协议规范生成处理类
-
测试替身:动态创建模拟类(Mock)用于测试
-
DSL 实现:领域特定语言的运行时类生成
5、注意事项
-
可读性:过度使用动态类会使代码难以维护
-
性能:动态创建类比静态定义稍慢
-
调试:动态生成的类可能更难调试
-
文档:需要额外文档说明动态行为