订单可变参考和分配的嵌套函数
问题描述:
从Google Style Guide上词法作用域:订单可变参考和分配的嵌套函数
嵌套Python函数可以指在包围 函数定义的变量,但是不能分配给他们。
此规范可以在这里看到:
def toplevel():
a = 5
def nested():
# Tries to print local variable `a`, but `a` is created locally after,
# so `a` is referenced before assignment. You would need `nonlocal a`
print(a + 2)
a = 7
nested()
return a
toplevel()
# UnboundLocalError: local variable 'a' referenced before assignment
扭转nested
两个语句的顺序摆脱这个问题:
def toplevel():
a = 5
def nested():
# Two statements' order reversed, `a` is now locally assigned and can
# be referenced
a = 7
print(a + 2)
nested()
return a
toplevel()
我的问题是,是什么关于Python的实现,告诉第一个函数a
将在本地声明(在print语句之后)?我的理解是,Python是逐行有效地解释的。那么,它不应该默认在代码中寻找非本地a
?
具体地说就是,如果我是使用只是参考(不分配),
def toplevel():
a = 5
def nested():
print(a + 2)
nested()
return a
toplevel()
莫名其妙print语句知道要引用封闭函数定义的非本地a
。但如果我在之后分配给当地的a
,那么该功能对于自己的功能来说就太聪明了。
答
我的理解是,Python被逐行有效地解释。
这不是正确的心智模式。
分析整个函数的主体以确定哪些名称引用局部变量,哪些不引用。
为了简化你的榜样,下面还给出了UnboundLocalError
:
def func():
print(a)
a = 2
func()
这里,func()
编译下面的字节码:
2 0 LOAD_FAST 0 (a)
3 PRINT_ITEM
4 PRINT_NEWLINE
3 5 LOAD_CONST 1 (2)
8 STORE_FAST 0 (a)
11 LOAD_CONST 0 (None)
14 RETURN_VALUE
与
def gunc():
print(a)
其编译比较一下到
2 0 LOAD_GLOBAL 0 (a)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE
观察a
的赋值缺席情况是如何将参考文献从局部变为全局的。
答
我的理解是,Python是有效地线
这就是你错了解释线。在任何解释开始之前,整个文件被编译为字节码。
此外,即使字节码编译通道不存在,print(a + 2)
也不会在看到a = 7
之前执行,因为它在函数定义中。到它实际尝试执行时,Python仍然知道a = 7
print(a + 2)
。
也许OP意思是字节码是按指令执行的,这是正确的。不是吗? – direprobs
@direprobs:它不像你想象的那么正确,因为函数调用(明确的或者隐含在'+'之类的东西中)通常会导致字节码指令在其他字节码指令的中间执行,但无论如何,我认为提问者确实意味着逐行。 – user2357112