Python 嵌套函数中变量引用和赋值的顺序
从词汇范围界定的角度来看: 嵌套Python函数可以引用在封闭函数中定义的变量 功能,但无法分配给它们 此规范可在此处看到:Python 嵌套函数中变量引用和赋值的顺序,python,python-3.x,scope,Python,Python 3.x,Scope,从词汇范围界定的角度来看: 嵌套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 nee
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
详细说明一下,如果我只使用引用(没有赋值)
不知何故,print语句知道引用封闭函数中定义的非局部a
。但是如果我在那一行之后分配给一个本地a
,这个函数就太聪明了
我的理解是Python是逐行有效解释的
这就是你错的地方。在任何解释开始之前,整个文件被编译成字节码
此外,即使字节码编译过程不存在,print(a+2)
也不会在看到a=7
之前执行,因为它在函数定义中。Python在实际尝试执行print(a+2)
时,仍然知道a=7
Python的一个特殊怪癖是,如果没有有效的global
语句,那么对名称的赋值总是进入最内部的范围。赋值不复制数据-它们只是将名称绑定到对象
我的理解是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
是如何将引用从本地转到全局的。可能是指字节码按正确的指令执行的语句。“不是吗?”DeRePrass:它不像你想象的那么正确,因为函数调用(显式的或隐式的,如<代码> +/COD> >)通常会导致字节码指令在其他字节码指令的中间执行,但无论如何,我认为发问者确实是逐行表示的。
2 0 LOAD_GLOBAL 0 (a)
3 PRINT_ITEM
4 PRINT_NEWLINE
5 LOAD_CONST 0 (None)
8 RETURN_VALUE