
On Wed, 1 Jun 2011, Georg Brandl wrote:
On 01.06.2011 06:52, Carl M. Johnson wrote:
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?
Because x += y is equivalent to
x = x.__iadd__(y)
and therefore an assignment is going on here. Therefore, it's only logical to treat it as such when determining scopes.
Off on a bit of a tangent here - this behaviour always bugged me: --> x = ([],) --> x[0] += ['a'] Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment --> x (['a'],) --> I understand by the definition why this happens as it does, but intuitively, I'd expect an operation to either fail and raise, or succeed and not. I see two possible ways to make this behave: we can look before we leap, and raise the exception before calling __iadd__, if the assigment would fail; or, we can change the definition to only perform the assignment if __iadd__ returns something other than self. Both these are, to some extent, incompatible language changes. Both change how I think about the original proposal: with the first option, it softens the argument about __iadd__ being called before the assignment, so strengthens the case for the status quo; with the second option, the definition of __iadd__ gets more complicated, making me less inclined to dive into this definition to explain the locality of the assigned variable, preferring it to be defined separately, and simply. Back from the tangent, I think Carl's proposal would make Python more difficult to understand rather than less, so -1 from me. /Paul