在列表上使用 += 时出现 UnboundLocalError。为什么直接调用 __iadd__ 就可以正常工作,这里需要 `nonlocal`?
UnboundLocalError when using += on list. Why is `nonlocal` needed here when directly calling __iadd__ works fine?
考虑这段代码:
def main():
l = []
def func():
l += [1]
func()
print(l)
if __name__ == '__main__':
main()
它将产生:
Traceback (most recent call last):
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 14, in <module>
main()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 11, in main
func()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 9, in func
l += [1]
UnboundLocalError: local variable 'l' referenced before assignment
这本身可以通过在 func
开头使用 nonlocal l
或 直接使用 __iadd__
而不是 [=16] 来解决=].
问题:为什么这里需要nonlocal
?
这让我很惊讶。
+=
是增强的 assignment 运算符;它大致翻译为:
def func():
l = l + [1]
如果您要用对 object.__iadd__()
的调用替换 l += [1]
,如果您要使用它,则不能忽略该调用的 return 值 正确:
def func():
l = l.__iadd__([1])
这两个翻译也需要一个 nonlocal
语句,因为它们都访问 l
并分配回 l
.
您可以忽略 object.__iadd__
的 return 值,因为列表对象是可变的;该列表已就地更改。但是在那种情况下你也可以使用 list.extend()
调用:
def func():
l.extend([1])
list.__iadd__()
,在幕后,在 returning self
.
之前调用 list.extend()
因为,在幕后,l += [1]
导致:
l = l + [1]
在分配给它之前引用了名称 l
;这就是为什么你会得到 UnboundLocalError
。
l.__iadd__
,另一方面,是一个简单的函数调用;它 不 执行赋值,因此不需要 nonlocal
来帮助查找名称 l
.
考虑这段代码:
def main():
l = []
def func():
l += [1]
func()
print(l)
if __name__ == '__main__':
main()
它将产生:
Traceback (most recent call last):
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 14, in <module>
main()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 11, in main
func()
File "/Users/tahsmith/Library/Preferences/PyCharm2017.1/scratches/scratch_21.py", line 9, in func
l += [1]
UnboundLocalError: local variable 'l' referenced before assignment
这本身可以通过在 func
开头使用 nonlocal l
或 直接使用 __iadd__
而不是 [=16] 来解决=].
问题:为什么这里需要nonlocal
?
这让我很惊讶。
+=
是增强的 assignment 运算符;它大致翻译为:
def func():
l = l + [1]
如果您要用对 object.__iadd__()
的调用替换 l += [1]
,如果您要使用它,则不能忽略该调用的 return 值 正确:
def func():
l = l.__iadd__([1])
这两个翻译也需要一个 nonlocal
语句,因为它们都访问 l
并分配回 l
.
您可以忽略 object.__iadd__
的 return 值,因为列表对象是可变的;该列表已就地更改。但是在那种情况下你也可以使用 list.extend()
调用:
def func():
l.extend([1])
list.__iadd__()
,在幕后,在 returning self
.
list.extend()
因为,在幕后,l += [1]
导致:
l = l + [1]
在分配给它之前引用了名称 l
;这就是为什么你会得到 UnboundLocalError
。
l.__iadd__
,另一方面,是一个简单的函数调用;它 不 执行赋值,因此不需要 nonlocal
来帮助查找名称 l
.