元类的__prepare__方法执行时机是什么?其返回值由谁使用?
__prepare__方法的执行时机
元类的__prepare__是整个类构建流程中最先被触发的钩子,执行时机早于类定义体内的任何代码运行:当Python解释器准备解析一个类的定义块时,会首先找到该类指定的元类,调用元类的__prepare__类方法,拿到返回值后才会继续后续的类构建操作。你示例的输出也完全符合这个顺序:打印before MyClass后第一个执行的就是in __prepare__,远早于类体内的in MyClass 1打印。
__prepare__返回值的用途与参数传递逻辑
__prepare__的返回值本质是类属性的临时命名空间容器,整个使用、传递流程都是Python解释器内置的类构建逻辑自动完成的,属于语言底层实现的调度,不需要开发者手动编写代码触发,具体流程如下:
- 解释器将
__prepare__返回的映射对象作为类的临时命名空间,后续所有类属性的写入都会操作这个对象 - 解释器自动向该命名空间写入类的内置默认属性,比如
__module__、__qualname__,你示例中前两个__setitem__打印就是这一步触发的 - 解释器逐行执行类定义体内的所有代码,所有在类体中定义的变量、方法、类属性,都会通过调用命名空间的
__setitem__方法写入该容器,你示例中的method1、method2写入,以及类体内的print语句执行都属于这一步 - 类体全部代码执行完成后,解释器会把已经填充完所有类属性的这个临时命名空间,作为第四个参数
classdict自动传入元类的__new__方法,你示例中最后打印in __new__就是这一步触发的
你提到调试时很难理清底层逻辑,是因为上述的整个调度流程都是CPython解释器的C语言层面实现的,Python级别的调试器(比如pdb、pythontutor)只能追踪Python代码的执行栈,所以看不到这部分的底层调用逻辑,只能通过打印语句观察行为。
默认情况下,如果元类没有自定义__prepare__方法,解释器会默认返回一个普通的dict实例作为临时命名空间。Python3.7之后普通dict默认保留插入顺序,因此早期需要用__prepare__自定义有序字典来记录类成员定义顺序的需求已经被原生支持,不过如果需要自定义命名空间的行为(比如自动去重类属性、自动给所有方法加装饰器等),仍然可以通过自定义__prepare__返回自定义映射类实现。
内容的提问来源于stack exchange,提问作者joseville
相关产品推荐
相关产品推荐

