【发布时间】:2015-08-31 09:50:31
【问题描述】:
这实际上源于这里关于 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 中做了一些挖掘(见下文),但我真的很想得到更接近明确答案的东西。
选项 1:直接调用
元类调用被硬连线到类解析中。如果是这样,有任何证据吗?
选项2:由type.__new__()调用
type_call() 中的代码调用type_new(),后者又调用_PyType_CalculateMetaclass()。这表明元类解析实际上是在调用type() 期间完成的,当时试图找出从type() 返回的值
这符合“类”是“返回对象的可调用对象”的概念。
选项 3:不同的东西
当然,我所有的猜测都可能完全错误。
我们在聊天中想出的一些例子:
示例 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 中的代码路径——然而——不同。
【问题讨论】:
-
FWIW,最初的讨论是关于
SomeClass()是否解析为SomeClass.__class__.__call__()(最终将委托给type.__new__(),或者 iit 解析为type.__call__()(这将委托给 @987654351 @)。 -
@brunodesthuilliers 我认为我们现在已经解决了这个问题,而且是前者。不过,仍有一些谜团:)
-
@dhke 好像我遗漏了什么... 愿意启发我吗?
-
@dhke 现在显然是 ;)
标签: python python-2.7 metaclass