元类编程
就讲type、类怎么创建的,还有元类实际能用在哪。
- 理解「类也是对象」和 type 的角色
- 理解类创建过程
- 能编写简单元类
- 掌握元类的替代方案(__init_subclass__)
元类编程
元类(metaclass)是「创建类的类」。在 Python 中,类本身也是对象,由元类创建。绝大多数情况下你都不需要元类,但理解它能让你看懂框架源码。
类也是对象
类创建过程
元类危险的地方:调试难,类创建时机比实例化早多继承时元类必须是父子关系,会冲突继承链上的元类会全部执行绝大多数场景都有更简单的方案替代
__init_subclass__:元类的轻量替代
元类的实际用途
元类的优先级:能用普通继承/装饰器解决的,不用 __init_subclass__;能用 __init_subclass__ 的,不用元类。元类只在框架级抽象中使用(ORM、序列化、API框架)。读框架源码时遇到 metaclass 不要慌,它就是拦截类创建过程的钩子。现代 Python 倾向于用 __init_subclass__ 和类装饰器替代元类。
元类冲突与 MRO
多继承时如果父类有不同元类,会报元类冲突:
# 元类冲突
class MetaA(type): pass
class MetaB(type): pass
class A(metaclass=MetaA): pass
class B(metaclass=MetaB): pass
# class C(A, B): pass # TypeError: metaclass conflict
# 解决:创建共同的子元类
class MetaAB(MetaA, MetaB): pass
class C(A, B, metaclass=MetaAB): pass # OK
# 规则:最终类的元类必须是所有父类元类的子类
# Python 会自动找最派生的元类Python 中所有类的元类是?
大多数场景下元类的推荐替代方案是?
资深工程师加餐
底层原理 · 大厂视角 · 工程经验,点卡片展开
@decorator 写在函数定义上方,它在「模块加载、函数被定义时」就执行一次,把原函数包装成新函数;之后每次调用,走的都是包装后的版本。带参数的装饰器本质是三层嵌套(外层收参数、中层收函数、内层收调用参数)。务必用 functools.wraps 保留原函数名和文档,否则调试栈和日志里全是 wrapper。
挑战任务
插件注册系统
就用 __init_subclass__ 实现插件自动注册系统,子类会自动加入注册表。
课后作业
单例元类
用元类实现线程安全的单例模式。