0

考虑这段代码:

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

这本身可以通过nonlocal l在开头使用func __iadd__直接使用而不是来解决+=

问题:这里为什么nonlocal需要?

这对我来说非常令人惊讶。

4

2 回答 2

3

+=是增广赋值运算符;它大致翻译为:

def func():
    l = l + [1]

如果您要替换l += [1]为对 的调用,如果您要正确object.__iadd__()使用它,则不能忽略该调用的返回值:

def func():
    l = l.__iadd__([1])

这两种翻译都需要一个nonlocal声明,因为 accessl和 assign back to都需要l

您可以忽略 的返回值,object.__iadd__因为列表对象是可变的;该列表已就地突变。但是在这种情况下你也可以使用list.extend()调用:

def func():
    l.extend([1])

list.__iadd__(),在被窝里,list.extend()回来之前打电话self

于 2017-05-22T07:34:01.810 回答
1

因为,在幕后,l += [1]导致:

l = l + [1]

它引用了l分配给之前的名称;这就是为什么你会得到UnboundLocalError.

l.__iadd__,另一方面,是一个简单的函数调用;它执行任务,因此无需nonlocal协助在哪里查找名称l

于 2017-05-22T07:34:18.063 回答