Scope, type and UnboundLocalError

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Sun Jul 9 15:04:51 EDT 2006


Paddy a écrit :
> Bruno Desthuilliers wrote:
> 
>>Frank Millman a écrit :
>>
>>>Paddy wrote:
>>>
>>>
>>>>Hi,
>>>>I am trying to work out why I get UnboundLocalError when accessing an
>>>>int from a function where the int is at the global scope, without
>>>>explicitly declaring it as global but not when accessing a list in
>>>>similar circumstances.
>>>>
>>>
>>>
>>>There has just been a long thread about this. I think I understand it
>>>now. Here is my explanation.
>>>
>>>Ignoring nested scopes for this exercise, references to objects (i.e.
>>>variable names) can exist in the local namespace or the global
>>>namespace. Python looks in the local namespace first, and if not found
>>>looks in the global namespace.
>>>
>>>Any name assigned to within the function is automatically deemed to
>>>exist in the local namespace, unless overridden with the global
>>>statement.
>>
>>And this even of the local bindings sequentially comes after another
>>access to the name, ie:
>>
>>g = 0
>>
>>def fun():
>>   x = g # UnboundLocalError here
>>   g += 1
>>   return x
>>
>>
>>>With the statement 'm = m + 1', as m is assigned to on the LHS, it is
>>>deemed to be local, but as m does not yet have a value on the RHS, you
>>>get Unbound Local Error.
>>
>>Right
>>
>>
>>>With the statement 'n[0] = n[0] + 1', n is not being assigned to,
>>
>>Right
>>
>>
>>> as it
>>>is mutable.
>>
>>n is effectively mutable, but this is totally irrelevant. In your
>>snippet, n is not 'assigned to', it's "mutated" (ie a state-modifying
>>method is called). The snippet:
>>
>>n[0] = n[0] + 1
>>
>>is syntactic sugar for
>>
>>n.__setitem__(0, n.__getitem__(0) + 1)
>>
>>IOW, it's just method calls on n.
> 
> 
> So,
> An assignment statement may assign an object to a name,

An assignment statement binds an object to a name.

> in which case
> the name is 'tagged' as being local,

Unless that names has been declared as global or lives in another 
namespace (ie is an element of a mutable collection or an attribute of 
another object).

> An assignment statement may mutate a mutable object already bound to a
> name, in which case the assignment will not 'tag' the name as  being
> local.

consider this code:

class Foo(object):
   def __init__(self, baaz):
     self.baaz = baaz

def bar(foo, bak):
   foo.baaz = bak

Which name is getting rebound here ? foo, or foo.baaz ?

> I guess Bruno, you mean irrelevant as in 'although only mutable objects
> can have their state modified; if n has a mutable value but the
> assignment statement changed the object referred to by n, then the name
> would be tagged as local'?

Unless the name has been declared as global, yes.



More information about the Python-list mailing list