Python可执行文件如何解析和执行脚本?

Jam*_*mie 3 python ipython python-2.7

假设我有以下脚本test.py

import my_library

bar = 12

def foo():
    nested_bar = 21

    my_library.do_things()

    def nested_foo():
        nested_bar += 11
        not_a_variable += 1
            {$ invalid_syntax

bar = 13
foo()
bar = 14
Run Code Online (Sandbox Code Playgroud)

我很好奇当我跑步时到底会发生什么python test.py。显然,Python 不只是逐行读取程序 - 否则它不会在实际执行程序之前捕获语法错误。但这使得解释器的工作显得有些模糊。我想知道是否有人能帮我解决问题。我特别想知道:

  1. Python 在什么时候意识到第 13 行有语法错误?

  2. Python 在什么时候读取嵌套函数并将它们添加到 的作用域中foo

  3. foo同样,Python遇到函数时如何将其添加到其命名空间而不执行它?

  4. 假设my_library是无效的导入。ImportErrorPython在执行任何其他命令之前是否一定会引发?

  5. 假设my_library是一个有效的模块,但它没有功能do_things。Python 在执行期间或之前什么时候会意识到这一点foo()

如果有人能给我提供有关 Python 如何解析和执行脚本的文档,我将非常感激。

Eev*_*vee 5

教程的模块部分中有一些信息,但我认为文档没有对此的完整参考。所以,这就是发生的事情。

\n\n

当您第一次运行脚本导入模块时,Python 会将语法解析为 AST,然后将其编译为字节码。它还没有执行任何操作;它只是将您的代码编译为基于堆栈的小型机器的指令。这是捕获语法错误的地方。ast(您可以在模块、token模块、compile内置函数、语法参考以及散布在其他各个地方的内容中看到所有这些内容的实质内容。)

\n\n

实际上,您可以独立于运行生成的代码来编译模块;这就是内置compileall方法的作用。

\n\n

So that\'s the first phase: compiling. Python only has one other phase, which is actually running the code. Every statement in your module, except those contained within def or lambda, is executed in order. That means that imports happen at runtime, wherever you happen to put them in your module. Which is part of the reason it\'s good hygiene to put them all at the top. Same for def and class: these are just statements that create a specific type of object, and they\'re executed as they\'re encountered, like anything else.

\n\n

The only tricky bit here is that the phases can happen more than once \xe2\x80\x94 for example, an import is only executed at runtime, but if you\'ve never imported that module before, then it has to be compiled, and now you\'re back in compile time. But "outside" the import it\'s still runtime, which is why you can catch a SyntaxError thrown by an import.

\n\n

Anyway, to answer your specific questions:

\n\n
    \n
  1. At compile time. When you run this as a script, or when you import it as a module, or when you compile it with compileall, or otherwise ask Python to make any sense of it. In practical terms, this can happen at any time: if you tried to import this module within a function, you\'d only get a SyntaxError when calling that function, which might be halfway through your program.

  2. \n
  3. 在执行期间foo,因为def并且class只是创建一个新对象并为其分配一个名称。但 Python 仍然知道如何创建嵌套函数,因为它已经编译了其中的所有代码。

  4. \n
  5. foo = lambda: 1 + 2与添加到名称空间而不执行它的方式相同。函数只是一个包含“code”属性 \xe2\x80\x94 的对象,实际上只是一个 Python 字节码块。您可以将code类型作为数据进行操作,因为它数据,独立于执行它。尝试查看函数,阅读数据模型.__code__的“代码对象”部分,甚至使用反汇编程序。(您甚至可以使用自定义局部变量和全局变量直接执行代码对象,或者更改函数使用的代码对象!)exec

  6. \n
  7. 是的,因为它import是一个像其他语句一样的普通旧语句,按顺序执行。但如果之前有其他代码,则该代码import将首先运行。如果它在一个函数中,那么在该函数运行之前您不会收到错误。请注意import,就像defand一样class,只是一种奇特的赋值形式。

  8. \n
  9. 仅在执行期间foo()。Python 无法知道其他代码是否会do_things在此之前向您的模块添加 a ,甚至my_library完全更改为其他对象。属性查找总是在您需要时即时完成,而不是提前完成。

  10. \n
\n