Reputation: 1723
Consider this code:
def main():
l = []
def func():
l += [1]
func()
print(l)
if __name__ == '__main__':
main()
It will produce:
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
This itself can be fixed by either using nonlocal l
at the start of func
or using __iadd__
directly instead of +=
.
Question: Why is nonlocal
needed here?
This is very surprising to me.
Upvotes: 0
Views: 74
Reputation: 1122392
+=
is the augmented assignment operator; it roughly translates to:
def func():
l = l + [1]
If you were to replace l += [1]
with a call to object.__iadd__()
, you can't ignore the return value of that call if you were to use it properly:
def func():
l = l.__iadd__([1])
Both of those translations also need a nonlocal
statement, because both access l
and assign back to l
.
You can get away with ignoring the return value of object.__iadd__
because list objects are mutable; the list is mutated in-place. But then you may as well use the list.extend()
call in that case:
def func():
l.extend([1])
list.__iadd__()
, under the covers, calls list.extend()
before returning self
.
Upvotes: 3
Reputation: 160467
Because, under the covers, l += [1]
leads to:
l = l + [1]
which references the name l
before that's assigned to; that's why you'll get the UnboundLocalError
.
l.__iadd__
, on the other hand, is a simple function call; it doesn't perform an assignment thereby negating the need for nonlocal
to assist in where to look for the name l
.
Upvotes: 1