我在外部函数中编写一个内部函数,然后发生了一些连接,即在向内部函数中的局部变量赋值时,发生了UnBoundLocalError。相反,如果我只是在内部函数中打印出局部变量,它就可以很好地工作。让我向您展示简化的代码。我知道这与Python中的LEGB规则有关,但是我仍然找不到原因。如果有人可以给我一些见解,我会非常感激。让我向您展示简化代码。
def outer1():
number = 10
def inner():
print(number)
inner()
def outer2():
number = 20
def inner():
if number >= 20:
number += 1
inner()
outer1()
函数运行良好,但是outer2()
函数抛出了UnboundLocalError: local variable 'number' referenced before assignment
。
我知道使用nonlocal
关键字可以解决此问题。但是还是有一些让我困惑的东西。为什么if
函数中的outer2()
语句没有像number
函数那样在外部函数中查找变量outer1()
。有人可以给我一些解释吗?
答案 0 :(得分:1)
在这种情况下,您需要使用nonlocal
语句:
def outer2():
number = 20
def inner():
nonlocal number
if number >= 20:
number += 1
inner()
要了解原因,请看一下字节码:
import dis
def outer2():
number = 20
def inner():
if number >= 20:
number
inner()
def outer3():
number = 20
def inner():
if number >= 20:
number = number + 1
inner()
def outer4():
number = 20
def inner():
nonlocal number
if number >= 20:
number = number + 1
inner()
>>> dis.dis(outer2)
2 0 LOAD_CONST 1 (20)
3 STORE_DEREF 0 (number)
3 6 LOAD_CLOSURE 0 (number)
9 BUILD_TUPLE 1
12 LOAD_CONST 2 (<code object inner at 0x7ff003b56b70, file "<stdin>", line 3>)
15 LOAD_CONST 3 ('outer2.<locals>.inner')
18 MAKE_CLOSURE 0
21 STORE_FAST 0 (inner)
6 24 LOAD_FAST 0 (inner)
27 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
30 POP_TOP
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
>>> dis.dis(outer3)
2 0 LOAD_CONST 1 (20)
3 STORE_FAST 0 (number)
3 6 LOAD_CONST 2 (<code object inner at 0x7ff003b56ae0, file "<stdin>", line 3>)
9 LOAD_CONST 3 ('outer3.<locals>.inner')
12 MAKE_FUNCTION 0
15 STORE_FAST 1 (inner)
6 18 LOAD_FAST 1 (inner)
21 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
24 POP_TOP
25 LOAD_CONST 0 (None)
28 RETURN_VALUE
>>> dis.dis(outer4)
2 0 LOAD_CONST 1 (20)
3 STORE_DEREF 0 (number)
3 6 LOAD_CLOSURE 0 (number)
9 BUILD_TUPLE 1
12 LOAD_CONST 2 (<code object inner at 0x7ff003af7e40, file "<stdin>", line 3>)
15 LOAD_CONST 3 ('outer4.<locals>.inner')
18 MAKE_CLOSURE 0
21 STORE_FAST 0 (inner)
7 24 LOAD_FAST 0 (inner)
27 CALL_FUNCTION 0 (0 positional, 0 keyword pair)
30 POP_TOP
31 LOAD_CONST 0 (None)
34 RETURN_VALUE
从这些示例中可以看到,尝试分配给变量(未声明为非本地变量)
产生MAKE_FUNCTION
操作码。但是只有闭包允许将访问变量移出当前范围。
您还可以阅读有关闭包here的更多信息。
注意:这已在Python 3.5中进行了测试;另请参阅有关在Python 3.6中将changes转换为MAKE_FUNCTION
和MAKE_CLOSURE
操作码的信息
答案 1 :(得分:0)
def outer2():
number = 20
def inner():
nonlocal number # this is the additional change required
if number >= 20:
number += 1
inner()
在python函数中,可以访问函数甚至方法中的“全局”变量,但不能为它们分配值,因为那样的话,该函数将寻找变量的本地副本。 错误的原因是该函数在其符号表条目中查找局部变量“ number”,但找不到它。
这通常可以通过使用global关键字来指定您正在编辑的变量具有全局范围来解决,但是由于该函数是在另一个函数中定义的,因此您将需要使用'nonlocal'关键字,这是另一种方法说要修改的变量不是该函数的局部变量,而是定义它的函数的局部变量,在本例中为external2。