了解Python如何“编译”或“解释”函数对象

时间:2014-02-24 04:31:17

标签: python function interpreter

我已阅读以下帖子,但我仍然不确定。

  1. Python Compilation/Interpretation Process

  2. Why python compile the source to bytecode before interpreting?

  3. 如果我有一个包含以下代码的Python文件myfunctions.py。

    x  = 3
    def f():
        print x
        x = 2
    

    然后,说$ python myfunctions.py完全正常。 但是现在对上面的文件做一个小改动。新文件如下所示。

    x  = 3
    def f():
        print x
        x = 2
    f() # there is a function call now
    

    这一次,代码发出错误。现在,我试图理解这种行为。到目前为止,这些是我的结论。

    • Python为x=3
    • 创建字节码
    • 它创建一个函数对象f,快速扫描并具有字节码,该字节码讨论f范围内的局部变量,但请注意,Python中所有语句的字节码都不太可能构建。
    • 现在,Python遇到一个函数调用,它知道这个函数调用是合法的,因为存在关于函数对象f及其局部变量的最小字节码。
    • 现在解释器负责执行字节码,但是从初始足迹开始,它知道x是一个局部变量,并说 - “为什么要在分配前打印?”

    有人可以对此发表评论吗?提前致谢。对不起,如果以前已经解决了这个问题。

2 个答案:

答案 0 :(得分:2)

当解释器读取函数时,对于它遇到的每个“名称”(变量),解释器决定该名称是 local 还是非本地。使用的标准非常简单......在正文的任何​​地方是否有一个赋值语句(禁止global语句)? e.g:

def foo():
    x = 3  # interpreter will tag `x` as a local variable since we assign to it here.

如果该名称有赋值语句,则该名称将标记为“local”,否则将标记为非本地名称。

现在,在您的情况下,您尝试打印标记为本地的变量,但是在实际到达关键赋值语句之前执行此操作。 Python查找本地名称,但找不到它,因此它会引发UnboundLocalError

Python是非常动态的,允许你做很多疯狂的事情,这是使它如此强大的一部分。这样做的缺点是,除非你实际上运行函数,否则检查这些错误变得非常困难 - 实际上,python已决定检查其他任何错误比函数运行之前的语法。这解释了为什么在实际调用函数之前,你永远不会看到异常。


如果希望python将变量标记为全局变量,则可以使用显式global 1 语句来执行此操作:

x = 3
def foo():
  global x
  print x
  x = 2

foo()  # prints 3
print x  # prints 2

1 python3.x进一步采用了这个概念,介绍了nonlocal关键字

答案 1 :(得分:1)

mgilson获得了答案的一半。

另一半是Python不会在函数(或函数对象)中查找错误,而不是执行错误。因此,在第一种情况下,由于未调用f(),因此不会检查操作顺序错误。

在这方面,它不像C和C ++,它要求所有内容都在前面完全声明。它有点像C ++模板,在实际实例化代码之前,可能无法找到模板代码中的错误。