CPython 源代码的Include/funcobject.h以下一条注释开头:
函数对象和代码对象不应与每个对象混淆 其他:
功能对象是通过执行'def'创建的 声明。他们在其
__code__
属性中引用了一个代码对象, 这纯粹是句法对象,即只不过是编译对象 一些源代码行的版本。每个源只有一个代码对象 代码“片段”,,但每个代码对象都可以用零或 许多功能对象仅取决于“ def”的次数 到目前为止,源代码中的语句已经执行。
我不太了解。
我在这里写下我的部分理解。可能有人完成它。
编译阶段。
我们有源文件 Test.py :
def a_func():
pass
解释器解析它并创建两个代码对象-一个用于Test.py
,一个用于a_func
。
Test.py
代码对象具有co_code
字段(已反汇编):
3 0 LOAD_CONST 0 (<code object a_func at 0x7f8975622b70, file "test.py", line 3>)
2 LOAD_CONST 1 ('a_func')
4 MAKE_FUNCTION 0
6 STORE_NAME 0 (a_func)
8 LOAD_CONST 2 (None)
10 RETURN_VALUE
现阶段未创建任何函数对象。
执行阶段。
函数对象是通过执行'def'语句创建的。
虚拟机到达MAKE_FUNCTION
指令时,它将创建函数对象:
typedef struct {
PyObject_HEAD
PyObject *func_code; /* A code object, the __code__ attribute */
PyObject *func_globals; /* A dictionary (other mappings won't do) */
PyObject *func_defaults; /* NULL or a tuple */
PyObject *func_kwdefaults; /* NULL or a dict */
PyObject *func_closure; /* NULL or a tuple of cell objects */
PyObject *func_doc; /* The __doc__ attribute, can be anything */
PyObject *func_name; /* The __name__ attribute, a string object */
PyObject *func_dict; /* The __dict__ attribute, a dict or NULL */
PyObject *func_weakreflist; /* List of weak references */
PyObject *func_module; /* The __module__ attribute, can be anything */
PyObject *func_annotations; /* Annotations, a dict or NULL */
PyObject *func_qualname; /* The qualified name */
} PyFunctionObject;
他们在自己的
__code__
属性中引用了一个代码对象,这是一个纯粹的语法对象,即仅是某些源代码行的编译版本。
,并将a_func
代码对象放入PyObject *func_code
字段中。现在,注释“功能对象和代码对象不相同”中的消息已清除。
每个源代码“片段”都有一个代码对象,,但是每个代码对象可以被零个或多个功能对象引用,这取决于到目前为止,源代码中的“ def”语句执行了多少次。
坚固的字体强调了我不理解的部分。
答案 0 :(得分:1)
如果我创建了一个lambda工厂(出于范围考虑,这是一个好主意):
def mk_const(k):
def const(): return k
return const
然后有一个用于mk_const
的代码对象和一个用于const
的代码对象,但是后者有许多函数对象作为对mk_const
的调用(包括0)。
(使用lambda
没什么区别,但是使用def
解释起来更容易。)
也可能是if
的结果:
if lib.version>=4:
def f(x): return lib.pretty(x)
else:
def f(x): return str(x) # fallback
这里有两个代码对象(加上一个用于模块的对象),但最多只能使用其中一个。