问题在于,当您在函数内分配变量名时,Python 假定您正在尝试创建一个新的局部变量,该变量将在外部范围内屏蔽一个名称相似的变量。由于+= 必须获取 mylist 的值才能对其进行修改,因此它会抱怨,因为尚未定义mylist 的本地版本。 MRAB's answer对语义给出了清晰的解释。
另一方面,当您执行mylist.__iadd__([1]) 时,您并没有在函数内分配新的变量名。您只是使用内置方法来修改已分配的变量名称。只要您不尝试为mylist 分配新值,就不会出现问题。出于同样的原因,如果outer 中的mylist 的定义是mylist = [1],那么mylist[0] = 5 行也可以在inner 内部工作。
但是请注意,如果您尝试在函数中的任何位置为 mylist 分配新值,mylist.__iadd__([1]) 确实会失败:
>>> outer()
>>> def outer():
... mylist = []
... def inner():
... mylist.__iadd__([1])
... mylist = []
... inner()
...
>>> outer()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in outer
File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'mylist' referenced before assignment
如果您想从包含范围内为变量分配新值,在 3.0+ 中,您可以使用 nonlocal,就像您使用 global 为全局变量分配新值一样范围。所以不要这样:
>>> mylist = []
>>> def inner():
... global mylist
... mylist += [1]
...
>>> inner()
>>> mylist
[1]
你这样做:
def outer():
mylist = []
def inner():
nonlocal mylist
mylist += [1]
inner()
print(mylist)
outer()