【问题标题】:The function object and the code object relation in CPythonCPython中函数对象与代码对象的关系
【发布时间】:2019-07-14 05:24:53
【问题描述】:

CPython 源代码的Include/funcobject.h 以下一条注释开头:

函数对象和代码对象不应相互混淆 其他:

函数对象是通过执行'def'来创建的 陈述。他们在__code__ 属性中引用了一个代码对象, 这是一个纯粹的句法对象,即只不过是一个编译的 一些源代码行的版本。每个源有一个代码对象 代码“片段”,但每个代码对象可以被零引用或 许多函数对象仅取决于“def”的次数 到目前为止,源中的语句已执行。

我不太明白。


我在这里写下我的部分理解。可能有人完成它。

  1. 编译阶段。

    我们有源文件Test.py

    def a_func():
        pass
    

    解释器对其进行解析并创建两个代码对象 - 一个用于Test.py,一个用于a_funcTest.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
    

    在这个阶段没有创建函数对象。

  2. 执行阶段。

    • 函数对象是通过执行'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”语句执行了多少次。

    我看不懂的部分用强字体强调。

【问题讨论】:

    标签: python cpython


    【解决方案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
    

    这里有两个代码对象(加上模块的一个),但最多使用一个。

    【讨论】:

      猜你喜欢
      • 2017-10-27
      • 2014-08-05
      • 2010-10-19
      • 2012-09-01
      • 2020-06-13
      • 1970-01-01
      • 2010-10-01
      • 2015-05-05
      • 2021-01-19
      相关资源
      最近更新 更多