Python元类编程
是什么
元类是类的类,即元类是创建类的类。在Python中,默认的元类是type。
元类(Metaclass)是 Python 中一个高级特性,它允许你控制类的创建过程。
作用
元类可以用来控制类的创建过程,比如修改类的属性、方法,或者添加新的功能。
简单案例:
"""
元类Meta在类MyClass被创建时,动态地给它添加了一个greet方法
"""
class Meta(type):
def __new__(cls, name, bases, dct):
dct["greet"] = lambda self: f"Hello from {name}"
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=Meta):
pass
obj = MyClass()
print(obj.greet()) # 输出:Hello from MyClass
工作过程
- 类创建阶段:通过
__prepare__
方法创建命名空间字典 - 类初始化阶段:
__new__
方法生成类对象,__init__
进行属性绑定 - 实例化阶段:
__call__
方法控制实例创建过程
from collections import OrderedDict
"""
类定义阶段:
__prepare__:创建有序字典存储类属性
__new__:构造类对象,修改命名空间(自动添加__doc__和__slots__)
__init__:初始化类对象,此时类属性已固定
实例化阶段:
__call__:接管实例创建过程
调用用户定义的__new__和__init__
添加额外实例属性_creation_time
扩展控制点:
在元类中可拦截/修改类属性定义(如Django ORM字段收集)
控制实例化时的额外处理(如单例模式、对象池等)
通过__prepare__保留属性顺序(对API文档生成很重要)
"""
class MetaLogger(type):
# -------------------- Phase 1: Class Preparation --------------------
@classmethod
def __prepare__(cls, name, bases, **kwargs):
"""Create and return a namespace dictionary with order preservation"""
print(f"Step-1: [__prepare__] Creating namespace | Class: {name} | Bases: {bases}")
return OrderedDict() # Preserve attribute declaration order
# -------------------- Phase 2: Class Construction --------------------
def __new__(cls, name, bases, namespace, **kwargs):
"""Construct and return the class object"""
print(f"\nStep-2: [__new__] Building class | Namespace keys: {list(namespace.keys())}")
# Auto-generate docstring if missing
if '__doc__' not in namespace:
namespace['__doc__'] = f"Auto-generated class {name}"
# Enforce __slots__ definition
# if '__slots__' not in namespace:
# namespace['__slots__'] = ()
# print("[__new__] Warning: __slots__ not defined, added empty tuple")
# Create class using modified namespace
new_class = super().__new__(cls, name, bases, dict(namespace))
# Add custom class-level metadata
new_class._meta_author = "MetaLogger"
return new_class
def __init__(cls, name, bases, namespace, **kwargs):
"""Initialize the class object"""
super().__init__(name, bases, namespace)
print(f"Step-3: [__init__] Initialized class | Final attributes: {dir(cls)[:4]}...\n")
# -------------------- Phase 3: Instance Creation --------------------
def __call__(cls, *args, **kwargs):
"""Control instance instantiation process"""
print(f"Step-4: [__call__] Creating instance | Args: {args}, Kwargs: {kwargs}")
# Create instance through normal inheritance chain
instance = super().__call__(*args, **kwargs)
# Attach instance metadata
instance._created_at = "2023-10-01"
print("Step-7: [__call__] Instance creation complete")
return instance
class DataModel(metaclass=MetaLogger):
"""Custom data model class"""
version = 1.0
def __new__(cls, value):
print("\nStep-5: [DataModel __new__] Allocating memory")
return super().__new__(cls)
def __init__(self, value):
print("Step-6: [DataModel __init__] Initializing instance")
self.value = value
if __name__ == "__main__":
print("\n========= Class Definition Phase =========")
print("\n========= Instantiation Phase =========")
obj = DataModel(42)
print("\n========= Final Instance Inspection =========")
print(f"Step-8: Instance attributes: {vars(obj)}")
print(f"Step-9: Class metadata: _meta_author={DataModel._meta_author}")
知识准备
需要提前了解 __slots__
和 __new__
。
深度使用
实现单例模式
"""
这个元类SingletonMeta确保了SingletonClass只有一个实例。
"""
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class SingletonClass(metaclass=SingletonMeta):
pass
obj1 = SingletonClass()
obj2 = SingletonClass()
print(obj1 is obj2) # 输出:True
自动注册类
这个元类AutoRegisterMeta会在每个类被创建时,自动将类添加到registry列表中
class AutoRegisterMeta(type):
registry = []
def __new__(cls, name, bases, dct):
new_cls = super().__new__(cls, name, bases, dct)
cls.registry.append(new_cls)
return new_cls
class MyClass1(metaclass=AutoRegisterMeta):
pass
class MyClass2(metaclass=AutoRegisterMeta):
pass
print(AutoRegisterMeta.registry) # 输出:[<class '__main__.MyClass1'>, <class '__main__.MyClass2'>]
强制类属性类型
这个元类TypeCheckMeta会在类被创建时,检查属性的类型,并在设置属性值时进行类型检查
class TypeCheckMeta(type):
def __new__(cls, name, bases, dct):
for attr_name, attr_value in dct.items():
if isinstance(attr_value, type):
def type_check(self, value):
if not isinstance(value, attr_value):
raise TypeError(f"{attr_name} must be of type {attr_value.__name__}")
setattr(self, attr_name, value)
dct[attr_name] = property(lambda self: getattr(self, f"_{attr_name}"), type_check)
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=TypeCheckMeta):
attr = int
obj = MyClass()
obj.attr = 10
print(obj.attr) # 输出:10
obj.attr = "not an int" # 抛出TypeError
自定义类的继承逻辑
通过元类可以控制类的继承行为,例如在类被继承时自动添加某些功能或限制继承的条件。
"""
这个元类RestrictiveMeta限制了类的继承,不允许多继承。
"""
class RestrictiveMeta(type):
def __new__(cls, name, bases, dct):
if len(bases) > 1:
raise TypeError("Multiple inheritance is not allowed")
return super().__new__(cls, name, bases, dct)
class Base(metaclass=RestrictiveMeta):
pass
class Child(Base):
pass
class GrandChild(Child, Base): # 会抛出TypeError
pass
实现类的元数据管理
元类可以用来为类添加元数据,这些元数据可以用于描述类的属性、方法、行为等,方便后续的反射操作或框架功能的实现。
"""
这个元类MetaDataMeta为类添加了一个meta属性,用于存储元数据。
"""
class MetaDataMeta(type):
def __new__(cls, name, bases, dct):
dct["meta"] = {"description": "This is a class with meta data"}
return super().__new__(cls, name, bases, dct)
class MyClass(metaclass=MetaDataMeta):
pass
print(MyClass.meta) # 输出:{'description': 'This is a class with meta data'}
Interface约束模式
"""
强制子类实现指定方法
"""
class InterfaceMeta(type):
def __new__(cls, name, bases, attrs):
required_methods = {'save', 'delete'}
for method in required_methods:
if method not in attrs:
raise TypeError(f"必须实现 {method} 方法")
return super().__new__(cls, name, bases, attrs)
class Repository(metaclass=InterfaceMeta):
def save(self): ...
def delete(self): ...
框架中的应用
Django ORM
Django的models.Model使用ModelBase元类实现字段注册和数据库映射
# django/db/models/base.py
"""
当定义class User(models.Model)时,元类自动将字段存储到_meta.fields,并生成数据库表结构
"""
class ModelBase(type):
def __new__(cls, name, bases, attrs):
# 收集字段到_meta属性
new_class = super().__new__(cls, name, bases, attrs)
if hasattr(new_class, 'Meta'):
meta_attrs = {}
for k, v in new_class.Meta.__dict__.items():
if not k.startswith('__'):
meta_attrs[k] = v
new_class._meta = Options(meta_attrs)
return new_class
SQLAlchemy Declarative
通过DeclarativeMeta元类实现ORM映射
# sqlalchemy/ext/declarative/api.py
"""
类属性中的Column对象会被自动收集生成SQL表结构
"""
class DeclarativeMeta(type):
def __init__(cls, classname, bases, dict_):
# 自动注册Column到__table__
if '_decl_class_registry' in dict_:
table_args = []
for k, v in dict_.items():
if isinstance(v, Column):
setattr(cls, k, v)
table_args.append(v)
cls.__table__ = Table(cls.__tablename__, metadata, *table_args)
super().__init__(classname, bases, dict_)
Pydantic数据验证
在BaseModel元类中实现数据验证逻辑
# pydantic/main.py
"""
该机制使得模型类能自动生成JSON Schema和验证规则
"""
class ModelMetaclass(type):
def __new__(cls, name, bases, namespace):
# 收集Field类型信息
fields = {}
for k, v in namespace.items():
if isinstance(v, FieldInfo):
fields[k] = v
namespace['__fields__'] = fields
return super().__new__(cls, name, bases, namespace)
当定义 FastAPI 的请求模型时
"""
元类会自动将 name 和 age 字段存入 __fields__ 属性,用于后续验证
"""
from pydantic import BaseModel
class UserCreate(BaseModel):
name: str
age: int = Field(gt=0) # 元类会捕获 Field 对象
Fastapi路由系统的元编程
FastAPI 的路由装饰器(如 @app.get
)通过 类装饰器模式 实现元编程,动态修改路由行为:
# FastAPI 源码中的装饰器核心逻辑
def get(path: str, **kwargs):
def decorator(func: Callable):
func.__fastapi_route__ = {
"path": path,
"methods": ["GET"]
}
return func
return decorator
当使用 @app.get("/users")
时,该装饰器会给视图函数添加路由元数据,后续由框架解析生成路由表
几点建议
__init_subclass__
替代元类
优先使用 - 当只需要在子类创建时执行简单逻辑时,
__init_subclass__
比元类更高效 - 减少元类继承层级,提高代码可读性
# 元类实现方式(较重量级)
class Meta(type):
def __new__(cls, name, bases, attrs):
attrs['registry'] = {} # 类级别注册表
return super().__new__(cls, name, bases, attrs)
class Base(metaclass=Meta):
pass
# 使用 __init_subclass__ 优化(更轻量)
class Base:
registry = {}
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.registry = {} # 同样实现类级别注册表
print(f"子类 {cls.__name__} 已注册")
class User(Base): pass # 输出:子类 User 已注册
__slots__
减少内存占用
利用 __slots__
会禁用__dict__
,无法动态添加新属性- 适合用于需要创建大量实例的类(如ORM模型)
class HeavyClass:
def __init__(self, x, y):
self.x = x
self.y = y
# 优化版本(内存减少40-50%)
class OptimizedClass:
__slots__ = ('x', 'y') # 显式声明允许的属性
def __init__(self, x, y):
self.x = x
self.y = y
# 内存对比测试
import sys
print(sys.getsizeof(HeavyClass(1,2))) # 典型输出:56
print(sys.getsizeof(OptimizedClass(1,2))) # 典型输出:48
延迟加载与缓存优化
- 将元类中的耗时计算(如字段扫描)改为按需执行
- 使用缓存机制避免重复计算
class LazyMeta(type):
_cache = {}
def __new__(cls, name, bases, attrs):
# 避免重复计算类属性
if name not in cls._cache:
# 模拟耗时操作
print("正在生成类结构...")
cls._cache[name] = super().__new__(cls, name, bases, attrs)
return cls._cache[name]
class Product(metaclass=LazyMeta):
pass
# 多次继承测试(仅第一次会执行耗时操作)
class Book(Product): pass # 输出:正在生成类结构...
class EBook(Product): pass # 无输出(使用缓存)
属性访问优化(描述符协议)
- 将元类中可能涉及的属性访问优化为延迟计算
- 避免在类创建阶段执行不必要的初始化
class CachedProperty:
"""替代 @property 的缓存版本"""
def __init__(self, func):
self.func = func
self.__name__ = func.__name__
def __get__(self, instance, owner):
if instance is None:
return self
# 计算结果并缓存
res = instance.__dict__[self.__name__] = self.func(instance)
return res
class DataModel:
@CachedProperty
def heavy_calculation(self):
print("执行耗时计算...")
return sum(i*i for i in range(10**6))
d = DataModel()
print(d.heavy_calculation) # 输出:执行耗时计算... 结果
print(d.heavy_calculation) # 直接读取缓存(无输出)
元类与生成器结合(内存敏感场景)
- 大数据处理框架中的内存优化
- 避免在元类中一次性加载全部数据
class StreamProcessorMeta(type):
def __new__(cls, name, bases, attrs):
# 优化数据流处理类的内存使用
if 'process' in attrs:
original_method = attrs['process']
# 将处理方法转换为生成器
def gen_wrapper(self):
for item in self.data_stream:
yield original_method(self, item)
attrs['process'] = gen_wrapper
return super().__new__(cls, name, bases, attrs)
class DataStreamer(metaclass=StreamProcessorMeta):
def __init__(self):
self.data_stream = range(1000000)
def process(self, item):
return item * 2
ds = DataStreamer()
for result in ds.process(): # 使用生成器逐项处理
pass # 内存占用极低
← Previous postPython中的魔术方法详解
Next post →Python中的方法解析顺序MRO详解