dhk*_*hke 11 python metaclass python-2.7
这实际上源于对SO的讨论.
精简版
def meta(name, bases, class_dict)
return type(name, bases, class_dict)
class Klass(object):
__metaclass__ = meta
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这就是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
Run Code Online (Sandbox Code Playgroud)
编辑2:正确的初始版本,正确派生Meta自type.
似乎没问题,但我不确定这是否符合我的想法.另外:使其行为与示例1相似的规范方法是什么?
编辑3:使用type.__new__(...)似乎按预期工作,这似乎也支持选项2.
任何对内部蟒蛇魔法有更深入了解的人都能启发我吗?
编辑: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
Run Code Online (Sandbox Code Playgroud)
所以操作码是BUILD_CLASS.现在让我们搜索该术语的源代码(在github镜像上轻松完成).
你会得到几个结果,但最有趣的是Python/ceval.c声明函数static PyObject * build_class(PyObject *, PyObject *, PyObject *);并有一个case语句BUILD_CLASS.搜索文件,你可以找到build_class从第4430行开始的函数定义.在第4456行,我们找到你要查找的代码:
result = PyObject_CallFunctionObjArgs(metaclass, name, bases, methods,
NULL);
Run Code Online (Sandbox Code Playgroud)
所以答案是元类由负责执行BUILD_CLASS操作码的函数解析并调用.
| 归档时间: |
|
| 查看次数: |
201 次 |
| 最近记录: |