Scope, type and UnboundLocalError

Paddy paddy3118 at netscape.net
Sun Jul 9 16:34:28 EDT 2006


Bruno Desthuilliers wrote:
> 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.

Thanks Bruno, that clears it up for me (I had purposefully left out the
global statement from my example, but should have included it in the
explanation).




More information about the Python-list mailing list