类也是对象。元类是制造类的类。理解这句话,就理解了元类的一半。
一、从 type() 说起 通常我们这样定义类:
但鲜为人知的是,class 关键字背后调用的其实是 type():
1 2 3 4 5 6 7 MyClass = type ("MyClass" , (object ,), { "x" : 42 , "greet" : lambda self : f"Hello, I'm {self.x} " }) obj = MyClass() print (obj.greet())
type(name, bases, dict) 的三个参数:
参数 含义 示例 name类名 "MyClass"bases父类元组 (object,)dict类属性字典 {"x": 42}
所以 class MyClass: 等价于 MyClass = type("MyClass", (object,), {...})。
二、元类:制造类的类 当 Python 执行 class MyClass(metaclass=Meta) 时:
flowchart TD
A["class MyClass<br/>(metaclass=Meta)"] --> B["Meta.__new__()"]
B --> C["创建类对象"]
C --> D["Meta.__init__()"]
D --> E["返回类对象"]
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#FFF9C4,stroke:#F9A825,color:#333
style C fill:#E8D5F5,stroke:#CE93D8,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#3331 2 3 4 5 6 7 8 9 10 11 class Meta (type ): def __new__ (mcs, name, bases, namespace, **kwargs ): print (f"Creating class: {name} " ) cls = super ().__new__(mcs, name, bases, namespace) return cls class MyClass (metaclass=Meta): x = 10
元类的第一个参数习惯上叫 mcs(metaclass),而不是 cls,以区分它创建的是类而不是实例。
三、__new__ vs __init__:该用哪个? 方法 时机 能不能修改类结构 典型用途 __new__类对象创建前 可以新增/删除属性 注册表、ORM 字段收集 __init__类对象创建后 只修改类属性 添加类方法、验证
99% 的场景用 __new__ 。因为你需要在类创建时做出干预:
1 2 3 4 5 6 7 8 class Meta (type ): def __new__ (mcs, name, bases, namespace, **kwargs ): cls = super ().__new__(mcs, name, bases, namespace) return cls
四、AI应用:Agent 注册表 在构建 Agent 系统时,我们希望根据类型动态获取 Agent 实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 class AgentRegistry (type ): """元类: 自动注册所有 Agent 子类""" _registry = {} def __new__ (mcs, name, bases, namespace, agent_type=None , **kwargs ): cls = super ().__new__(mcs, name, bases, namespace) if agent_type: mcs._registry[agent_type] = cls print (f"Registered Agent: {agent_type} -> {name} " ) return cls @classmethod def get_agent (mcs, agent_type: str ): """根据类型获取 Agent 类""" return mcs._registry.get(agent_type) @classmethod def list_agents (mcs ): """列出所有可用的 Agent 类型""" return list (mcs._registry.keys()) class BaseAgent (metaclass=AgentRegistry): """所有 Agent 的基类""" pass class ReasoningAgent (BaseAgent, agent_type="reasoning" ): """推理型 Agent""" def think (self, prompt: str ) -> str : return f"[Reasoning] {prompt} " class CreativeAgent (BaseAgent, agent_type="creative" ): """创造型 Agent""" def generate (self, prompt: str ) -> str : return f"[Creative] {prompt} " print (f"Available agents: {AgentRegistry.list_agents()} " )reasoning = AgentRegistry.get_agent("reasoning" )() print (reasoning.think("Solve this problem" ))
运行输出:
1 2 3 4 Registered Agent: reasoning -> ReasoningAgent Registered Agent: creative -> CreativeAgent Available agents: ['reasoning', 'creative'] [Reasoning] Solve this problem
工作原理 :当 Python 执行 class ReasoningAgent(..., agent_type="reasoning") 时:
检测到 agent_type 关键字参数 调用 AgentRegistry.__new__ 将类存入 _registry 返回新类 这样我们就能在运行时通过字符串动态获取 Agent 类。
五、工具自动发现元类 同样的思路用于自动发现和注册工具插件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class ToolRegistry (type ): _tools = {} def __new__ (mcs, name, bases, namespace, tool_name=None , **kwargs ): cls = super ().__new__(mcs, name, bases, namespace) if tool_name: cls.tool_name = tool_name mcs._tools[tool_name] = cls return cls class BaseTool (metaclass=ToolRegistry): """工具基类""" pass class CalculatorTool (BaseTool, tool_name="calculator" ): def execute (self, expr: str ) -> str : return str (eval (expr)) class SearchTool (BaseTool, tool_name="search" ): def execute (self, query: str ) -> str : return f"Search results for: {query} " print (f"Tools: {list (ToolRegistry._tools.keys())} " )calc = ToolRegistry._tools["calculator" ]() print (calc.execute("2+2" ))
运行输出:
1 2 Tools: ['calculator', 'search'] 4
六、ORM 字段注册:经典案例 元类在 ORM 框架中的应用非常典型:
flowchart TB
A["class User<br/>(Model)"] --> B["ORMMeta.__new__()"]
B --> C["遍历类属性"]
C --> D{"是 Field?"}
D -->|"是"| E["收集到 _fields"]
D -->|"否"| F["跳过"]
E --> G["返回类"]
F --> G
style A fill:#C7CEEA,stroke:#9FA8DA,color:#333
style B fill:#FFF9C4,stroke:#F9A825,color:#333
style E fill:#B5EAD7,stroke:#80CBC4,color:#3331 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Field : """字段描述符基类""" def __init__ (self, column_type ): self .column_type = column_type self .name = None def __set_name__ (self, owner, name ): self .name = name class ORMMeta (type ): """ORM 元类: 自动收集字段并创建表结构""" def __new__ (mcs, name, bases, namespace, **kwargs ): cls = super ().__new__(mcs, name, bases, namespace) cls._fields = {} for attr_name in dir (cls): attr = getattr (cls, attr_name) if isinstance (attr, Field): cls._fields[attr_name] = attr return cls class Model (metaclass=ORMMeta): pass class User (Model ): name = Field("VARCHAR(100)" ) age = Field("INT" ) def __init__ (self, name, age ): self .name = name self .age = age print (f"User fields: {list (User._fields.keys())} " )
七、总结 场景 元类的作用 Agent 注册表 自动注册所有 Agent 子类,运行时动态获取 工具发现 自动收集所有工具插件 ORM 自动收集字段,生成表结构 插件系统 动态加载和管理插件
元类的核心逻辑 :class X(metaclass=M) → M.__new__(M, "X", bases, ns, **kwargs) → 返回类
描述符让我们控制属性访问,元类让我们控制类创建。两者结合,几乎可以实现任何自定义行为。下一篇文章我们来看 Protocol——Python 的结构化类型系统。
📚 Python AI教程 系列导航 本文是《Python AI教程》系列第 10/14 篇。
📖 全部 14 篇目录(点击展开) (一)闭包与装饰器 (二)上下文管理器 (三)生成器与迭代器 (四)类型提示 (五)Dataclass 与 attrs (六)async/await (七)Threading 与 Multiprocessing (八)函数式编程 (九)描述符协议 (十)元类 ← 当前 (十一)Protocol与结构化类型 (十二)异常链与日志 (十三)缓存艺术 (十四)组合模式实战