2

我得到了 python 执行的意外行为。

if True:
    print("Hello")
else:
    I am an error. what can you do about it?

现在,此代码不会引发 SyntaxError,因为控件永远不会进入 else 语句。在像 C++ 这样的编译语言中,它会出错。即使在 Java 中,未使用的代码也是一个错误。但不是在 Python 中。

现在在这种情况下:

x = 10
def foo():
    print(x)
    x += 1

print 语句引发了此处指定的 UnboundLocalError 。按照前面的逻辑,这个错误应该直到控件遇到x+=1才出现。但它确实如此,就像在任何其他编译语言中一样。

那么如何确定代码何时以编译或解释的方式运行?

编辑: 如果它被编译成字节码 .pyc 文件然后被解释。那为什么没有检测到第一个例子的 else 语句呢?

4

4 回答 4

2

对面的。Python 在执行前将源代码编译成字节码。第一种情况会在编译阶段引发语法错误。

在第二种情况下,编译器看到它x在函数中被修改,因此它绑定x到函数对象。每次调用函数时都会创建函数命名空间,但变量仅在分配时出现。只有当您执行时print(x),python 才会意识到您正在请求一个尚未分配的局部变量。当并非所有执行路径都设置了应有的变量时,这是一个常见错误。

稍微修改示例,有时设置了局部变量,有时则没有。设置后,您会在局部变量中看到变量并且打印有效。未设置时,变量不在本地,打印失败。

x = 10
def foo(val):
    if val:
        x = 1
    print(val, 'before', locals())
    print(x)
    print(val, 'after')
    x += 1

foo(True)
foo(False)

输出

True before {'val': True, 'x': 1}
1
True after
False before {'val': False}
Traceback (most recent call last):
  File "o.py", line 11, in <module>
    foo(False)
  File "o.py", line 6, in foo
    print(x)
UnboundLocalError: local variable 'x' referenced before assignment
于 2016-11-27T07:50:47.267 回答
1

它总是按解释运行;但第一步是在整个文件上调用语法检查器,生成字节码文件。

在 python 2.7 和 3.5 中,您放在顶部的代码将导致语法错误:

python3 junk.py
  File "junk.py", line 4
    I am an error. what can you do about it?
              ^
SyntaxError: invalid syntax

在 python 中应该不可能出现“运行时”语法错误;实现这一点的唯一方法是动态导入有语法错误的模块。

我不确定我是否理解您的问题,但第二种情况的错误是运行时错误;int x = 0; y = 10/x;就像在 C 中做的一样;变量作用域(“此时 x 是否存在?”)在 python 中的语法解析期间未解析。

--

编辑; 这是我终端的转储:

Clank:tmp doug$ cat junk.py
if True:
    print("Hello")
else:
    I am an error. what can you do about it?

Clank:tmp doug$ python junk.py
  File "junk.py", line 4
    I am an error. what can you do about it?
       ^
SyntaxError: invalid syntax

Clank:tmp doug$ python3 junk.py
  File "junk.py", line 4
    I am an error. what can you do about it?
       ^
SyntaxError: invalid syntax
于 2016-11-27T07:29:12.633 回答
1

好的,在阅读了 Doug 和 Jim 的回答后,我想我知道这是如何工作的。首先,所有示例都在 REPL 中工作(Ipython,默认)

文件:如果你把它写在一个文件中:

if True:
    print("Hi")
else:
    I am an error. What can you do about it?

并运行该文件,它会抛出一个 SyntaxError。这证明了每当我们从文件中执行 python 代码时,它都会生成一个字节码,并且由于 else 中的语句不是有效的 python 表达式,我们会得到一个 SyntaxError。

REPL:使用 REPL,事情变得有点依赖。在 python 解释器中,如果你输入

>>>def foo():
       if True:
           print("Hey")
       else:
           I am an error. What can you do about it?
>>>foo()
Hey

成功执行意味着没有字节码,对吗?坚持,稍等。

如果你这样写:

>>>x = 10
>>>def foo():
       print(x)
       x += 1
>>>foo()

和繁荣!一切都崩溃了,您在 print(x) 语句中得到 UnboundLocalError 。这意味着字节码在那里。

那么这里到底发生了什么?

如果 python 发现一个变量的单个出现,它会尝试通过首先读取所有变量来优化其工作。因此,在第二个示例中,当代码遇到 print(x) 时,它会尝试查找 x 上的所有操作。很快它就找到了语句 x+=1。由于在局部范围内没有提及 x 并且如果没有明确提及,python 永远不会在全局范围内查找变量,我们有

UnboundLocalError: local variable 'x' is referenced before assignment 

确凿的证明

如果我们这样写:

>>>x = 10
>>>def foo():
      if True:
          print(x)
      else:
          x+=1
>>>foo()
UnboundLocalError: local variable 'x' referenced before assignment

而已!

x+=1 永远不会被执行,但是由于 print 语句打印 x 并且另一个引用 (x+=1) 是问题,因此在打印值之前遇到了错误。第一种情况在 REPL 中没有 SyntaxError 时运行良好,因为它从不费心查看 else 语句,因为它无关紧要。

于 2016-11-27T13:28:41.833 回答
0

如果您通过一些简短的交互式 REPL(而不是 Python 的默认 REPL)运行它,您可能会使其实际执行而没有错误(IPython例如,s' qtconsole 允许它没有问题)。为什么允许这样做完全取决于 REPL 及其实现。

在 Python 中,这一个SyntaxError; 不能为它生成任何字节码:

s ="""
i= 1
if i:
    print("Hello")
else:
    I am an error. what can you do about it?
"""
c = compile(s, '', mode='exec')
  File "<string>", line 6
    I am an error. what can you do about it?
       ^
SyntaxError: invalid syntax

语法特别不允许它,允许在它们之间放置带有空格的字符串文字(Python 后来将其连接起来),名称不是(当然允许单独使用单个名称)。简而言之,这在解析阶段失败了:

from parser import suite
st = suite(s)
  File "<string>", line 6
    I am an error. what can you do about it?
       ^
SyntaxError: invalid syntax

当 Python 看到两个名称被空格隔开时,它不知道该怎么做,空格并不意味着任何操作(str文字除外)。

于 2016-11-27T10:08:46.427 回答