Python 中的元类(Metaclass)是什么?
元类是"类的类"——控制类如何被创建。继承 type 定义元类,通过 __new__/__init__ 在类创建时干预。典型用途:单例、注册表、ORM。本文用例子讲清楚。
元类是创建类的"模板":普通类创造实例,元类创造类。Python 中 type 就是默认元类——你写的每个类都是 type 的实例。自定义元类可以在类被创建时修改它(添加方法、注册、强制规则)。
一个例子:单例元类
class Singleton(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 Logger(metaclass=Singleton):
pass
a = Logger()
b = Logger()
print(a is b) # True——永远只有一个实例
Logger(...) 调用的是元类的 __call__,在这里拦截实现实例缓存。
元类的钩子
class MyMeta(type):
def __new__(mcs, name, bases, attrs):
# 类创建时:可以修改属性、添加方法
attrs['version'] = '1.0'
return super().__new__(mcs, name, bases, attrs)
def __init__(cls, name, bases, attrs):
# 类创建后:注册、校验
super().__init__(name, bases, attrs)
实际用途
- ORM:Django/SQLAlchemy 用元类把类属性(Field)转成表结构定义;
- 插件注册:类创建时自动加入注册表;
- 单例:如上例;
- 接口强制:检查子类必须实现某些方法(ABC 的底层机制)。
什么时候不要用
Tim Peters 名言:"元类是更深层次的魔法,99% 的用户永远不需要考虑它。"大多数需求用装饰器、类装饰器、__init_subclass__ 就能实现,更简单:
# 多数"注册子类"的需求用 __init_subclass__ 就够
class Plugin:
registry = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
Plugin.registry.append(cls)
常见问题(FAQ)
Q:元类和继承有什么区别?
A:继承定义"类与类"的 is-a 关系;元类定义"类怎么被造出来"。正交的两个概念。
Q:type 到底是什么?
A:type 既是类型检查函数,又是所有类的元类。type(MyClass) 返回 type,type(type) 也返回 type(自举)。
Q:面试外的日常开发需要懂吗?
A:理解概念即可。日常写业务代码几乎用不到自定义元类,但读懂框架源码(Django models)需要这个知识。