[Python-ideas] Why does += trigger UnboundLocalError?

Carl M. Johnson cmjohnson.mailinglist at gmail.com
Wed Jun 1 06:52:05 CEST 2011


We all know that the following code won't work because of UnboundLocalError
and that to get around it, one needs to use nonlocal:

>>> def accum():
...     x = 0
...     def inner():
...         x += 1
...         return x
...     return inner
...
>>> inc = accum()
>>> inc()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'x' referenced before assignment

But why does this happen? Let's think about this a little more closely: +=
is not the same as =. A += can only happen if the left-hand term was already
defined. So, why does the compiler treat this as though there were an
assignment inside the function? Compare:

>>> def accum():
...     x = []
...     def inner():
...         x.append(1)
...         return x
...     return inner
...
>>> inc = accum()
>>> inc()
[1]
>>> inc()
[1, 1]
>>> inc()
[1, 1, 1]

So, if I changed += to .append, the code suddenly works fine. Heck, I could
also change it to x.__iadd__ if x happens to have that attribute.

As we all know, adding an = anywhere to the function bound will cause x to
be considered a local. So, for example, we can make the .append example fail
by adding some unreachable code:

>>> def accum():
...     x = []
...     def inner():
...         x.append(1)
...         return x
...         x = 0 #Won't ever be reached, but will cause x to be considered
a local
...     return inner
...
>>> inc = accum()
>>> inc()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'x' referenced before assignment

So, my proposal is that += by itself should not cause x to be considered a
local variable. There should need to be a normal = assignment for the
compiler to count x as a local. If the objection to my proposal is that I'm
being "implicit and not explicit" because it would be like there's an
implicit "nonlocal," my rebuttal is that we already have "implicit"
nonlocals in the case of .append.

-- Carl Johnson
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20110531/5c3ac55b/attachment.html>


More information about the Python-ideas mailing list