__prepare__ 是元类的类方法,用于返回有序命名空间映射以保证类体成员定义顺序;python 3.6+ 默认 dict 保序,3.5 及以前需用 ordereddict;它必须返回支持 __setitem__ 和迭代的 mapping 对象,且每次调用须返回新实例。

Python 3.6+ 默认用 dict 保留类体中成员的定义顺序,所以多数情况下你根本不需要手动干预 —— 但如果你的目标是兼容 Python 3.5 或更早版本,或者想显式控制顺序(比如注入自定义逻辑),__prepare__ 才真正有用。
为什么 __prepare__ 能保留顺序?
Python 在执行 class 语句时,会先调用元类的 __prepare__ 方法获取一个命名空间映射对象,再把所有类体语句(如 attr = 1、def method(): ...)按出现顺序写入该映射。只要这个映射本身保持插入顺序,顺序就保住了。
在 Python 3.6+,普通 dict 已保证插入顺序;但在 3.5 及之前,必须用 collections.OrderedDict 显式替代。
-
__prepare__必须是类方法(用@classmethod修饰) - 返回值必须是 mapping 类型(支持
__setitem__和迭代) - 不能返回普通
dict(3.5- 中不保序),也不能返回非 mapping 对象(会触发TypeError)
Python 3.5 兼容写法:用 OrderedDict
这是最常见也最稳妥的用法,尤其当你需要支持旧版本或明确依赖顺序时:
from collections import OrderedDict <p>class OrderedMeta(type): @classmethod def <strong>prepare</strong>(cls, name, bases): return OrderedDict() </p>
然后这样使用:
华为云 Python SDK 查询工具。自动发现已安装 SDK 的服务包、Client类、API 方法、入参详情、类信息(__init__ 参数、属性、类型、描述),支持关键字搜索,快速定位目标 API 使用方法。
class Example(metaclass=OrderedMeta):
c = 3
a = 1
b = 2
<p>print(list(Example.<strong>dict</strong>.keys())) # ['c', 'a', 'b'](Python 3.5 下也成立)
</p>
- 注意:
__dict__是只读的 proxy,实际顺序由__prepare__返回的 dict 决定 - 不要在
__prepare__中传参或做复杂初始化——它只接收name和bases,且必须快速返回 - 如果元类还重写了
__new__,记得别意外覆盖掉__dict__的顺序(比如用dict()重建)
Python 3.6+ 中 __prepare__ 还有必要吗?
大多数情况没必要 —— 普通 dict 就够了,但以下场景仍需显式实现:
- 你想在成员写入前做拦截(例如记录每个属性的声明位置)
- 你需要返回带额外行为的 mapping(比如自动转换键名、拒绝重复键)
- 你正在写一个框架,要统一处理所有子类的定义顺序,且需跨版本兼容
例如,记录每个成员首次出现的行号:
class TracingMeta(type):
@classmethod
def __prepare__(cls, name, bases):
class TracingDict(dict):
def __setitem__(self, key, value):
if key not in self:
self[key] = {'value': value, 'line': len(self)}
else:
super().__setitem__(key, value)
return TracingDict()
这种定制无法靠默认 dict 实现,必须通过 __prepare__ 注入。
容易踩的坑:返回值类型和生命周期
__prepare__ 返回的对象会被 Python 解释器直接用于执行类体语句,因此:
- 不能返回不可变对象(如
frozenset),否则赋值时报TypeError: 'frozenset' object does not support item assignment - 不能返回自己构造的、未实现完整 mapping 接口的对象(缺
__iter__或keys()会导致AttributeError) - 不要在
__prepare__中缓存或复用同一个 mapping 实例——每次class定义都应获得全新实例 - 返回的 mapping 不会自动变成类的
__dict__;Python 最终会用它构建真正的__dict__,但中间可能被__new__或__init_subclass__修改
最安全的做法:始终返回干净的 OrderedDict()(兼容老版本)或 {}(仅限 3.6+ 且无定制需求),其余逻辑放在 __new__ 或 __init_subclass__ 中处理。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










