gpt4 book ai didi

python - 谁调用元类

转载 作者:太空狗 更新时间:2023-10-29 18:08:40 25 4
gpt4 key购买 nike

这实际上源于这里关于 SO 的讨论。

精简版

def meta(name, bases, class_dict)
return type(name, bases, class_dict)

class Klass(object):
__metaclass__ = meta

meta() 在执行 Klass 类声明时调用。

(python 内部)代码的哪一部分实际上调用了 meta()

长版

当类被声明时,一些代码必须进行适当的属性检查并查看是否有在类型上声明的 __metaclass__。如果存在,它必须使用众所周知的 (class_name, bases, class_dict) 属性对该元类执行方法调用。我不太清楚哪个代码负责该调用。

我已经在 CPython 中做了一些挖掘(见下文),但我真的很想得到更接近确定答案的东西。

方式一:直接调用

元类调用硬连接到类解析中。如果是这样,是否有任何证据可以证明这一点?

选项2:由type.__new__()调用

type_call() 中的代码电话 type_new()依次调用 _PyType_CalculateMetaclass() .这表明元类解析实际上是在调用 type() 期间尝试找出要从 type()

返回的值时完成的

这符合“类”是“返回对象的可调用对象”的概念。

选项 3:不同之处

当然,我所有的猜测都可能完全错误。

Some example cases that we came up with in chat:

示例 1:

class Meta(type):
pass

class A:
__metaclass__ = Meta

A.__class__ == Meta

这就是 Meta.__new__() 返回的结果,所以这看起来是合法的。元类将自己设置为 A.__class__

示例 2:

class Meta(type):
def __new__(cls, class_name, bases, class_dict):
return type(class_name, bases, class_dict)

class A(object):
__metaclass__ = Meta

A.__class__ == type

编辑 2:正确的初始版本,从 type 正确派生 Meta

看起来还不错,但我不太确定这是否符合我的预期。另外:使它像示例 1 中那样运行的规范方法是什么?

编辑 3:使用 type.__new__(...) 似乎按预期工作,这似乎也支持选项 2。

任何对内部 python 魔术有更深入了解的人都可以启发我吗?

编辑:A 关于元类的相当简洁的入门:http://blog.ionelmc.ro/2015/02/09/understanding-python-metaclasses/ .还有一些非常好的图表、引用资料,还强调了 python 2 和 3 之间的区别。

编辑 3:下面有一个针对 Python 3 的好答案。Python 3 使用 __build_class__创建一个类对象。代码路径在 Python 2 中有所不同。

最佳答案

您可以相对轻松地找到答案。首先,让我们找到构建类的操作码。

>>> def f():
class A(object):
__metaclass__ = type

>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 1 ('A')
3 LOAD_GLOBAL 0 (object)
6 BUILD_TUPLE 1
9 LOAD_CONST 2 (<code object A at 0000000001EBDA30, file "<pyshell#3>", line 2>)
12 MAKE_FUNCTION 0
15 CALL_FUNCTION 0
18 BUILD_CLASS
19 STORE_FAST 0 (A)
22 LOAD_CONST 0 (None)
25 RETURN_VALUE

所以操作码是BUILD_CLASS。现在让我们搜索该术语的来源(在 github mirror 上很容易完成)。

您会得到一些结果,但其中最有趣的是 Python/ceval.c,它声明了函数 static PyObject * build_class(PyObject *, PyObject *, PyObject *); 并且有一个 case 语句用于BUILD_CLASS。搜索文件,您可以找到从第 4430 行开始的 build_class 的函数定义。在第 4456 行,我们找到了您要查找的代码:

result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods,
NULL);

所以答案是元类由负责执行 BUILD_CLASS 操作码的函数解析和调用。

关于python - 谁调用元类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30852985/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com