Python是否在模块中隐式返回None?

Jim*_*ard -1 python bytecode module python-2.7 python-3.x

dis当我注意到为模块生成的字节码时,我正在使用模块的Python字节码.给出一个名为的小测试模块mod.py:

if __name__ == "__main__":
    print("Hello World")
Run Code Online (Sandbox Code Playgroud)

我用它为compile()函数创建了一个代码对象:

>>> cobj = compile(open("mod.py").read(), "mod", "exec")
Run Code Online (Sandbox Code Playgroud)

然后,反汇编代码对象以查看字节码:

>>> dis.dis(cobj)
  1           0 LOAD_NAME                0 (__name__)
              3 LOAD_CONST               0 ('__main__')
              6 COMPARE_OP               2 (==)
              9 POP_JUMP_IF_FALSE       22

  2          12 LOAD_NAME                1 (print)
             15 LOAD_CONST               1 ('Hello World')
             18 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
             21 POP_TOP
        >>   22 LOAD_CONST               2 (None)
             25 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

让我印象深刻的是最后两个命令LOAD_CONSTRETURN_VALUE,如果我的理解是正确的,将常None值栈,因此返回.

模块是否隐式返回None,如果是,为什么?

Jim*_*ard 6

是的,简而言之,模块会隐式返回None,以便内部的大评估循环ceval.c能够检测到当前帧何时完成并终止.

有趣的是,即使从终端解释了一个完全为空的python文件,你也可以看到这个:

jim@lpt> touch file.py
jim@lpt> python -m dis file.py
1           0 LOAD_CONST               0 (None)
            3 RETURN_VALUE    
Run Code Online (Sandbox Code Playgroud)

此行为不仅限于模块,而是适用于任何可以形成代码块的行为 ; 这包括类定义:

>>> from dis import dis
>>> co = compile("class mycls: pass", filename = "stdin", mode = "exec")
>>> dis(co.co_consts[0])  # co_consts[0] contains class definition
  1           0 LOAD_NAME                0 (__name__)
              3 STORE_NAME               1 (__module__)
              6 LOAD_CONST               0 ('mycls')
              9 STORE_NAME               2 (__qualname__)
             12 LOAD_CONST               1 (None)
             15 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

职能机构:

>>> def foo(): pass

>>> dis(foo)
  1           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

也就是说,RETURN_VALUE字节码命令终止正在执行的当前块,LOAD_CONST并将堆栈顶部的值返回给被调用者(如果存在).

唯一需要注意的是,指定自定义返回值仅允许用于函数,在类定义和模块中,返回值没有太多用途,因此尝试在适当的位置指定一个结果SyntaxError.


对于对此源代码感兴趣的人,您可以通过逐步执行compile.c以下文档中定义的函数来找到它compile.c:

 * The primary entry point is PyAST_Compile(), which returns a
 * PyCodeObject.  The compiler makes several passes to build the code
 * object:
 *   1. Checks for future statements.  See future.c
 *   2. Builds a symbol table.  See symtable.c.
 *   3. Generate code for basic blocks.  See compiler_mod() in this file.
 *   4. Assemble the basic blocks into final code.  See assemble() in
 *      this file.
 *   5. Optimize the byte code (peephole optimizations).  See peephole.c
Run Code Online (Sandbox Code Playgroud)

相关步骤3.4.compiler_modassemble功能