Scope in 2.2.1

Alex Martelli aleax at aleax.it
Sat May 11 04:52:29 EDT 2002


David LeBlanc wrote:

> The 2.2.1 Python doc in Appendix A1 says:
> "If a name binding operation occurs anywhere within a code block, all uses
> of the name within the block are treated as references to the current
> block. This can lead to errors when a name is used within a block before
> it is bound."
> 
> def foo():                    #block
> bar = 0               #binding
> 
> bar now is a reference to foo? Somehow, I doubt that!

Right -- the wording of A1 may not be optimal here.


> My other question pertaining to this paragraph is: what errors can occur
> if a name is used before it's bound?

NameError, or its subclass UnboundLocalError specifically.


> My other question is illustrated by this code:
> 
>>>> def foo():
> ...     bar = 0
> ...     bar2 = 0
> ...     def fee():
> ...             print bar
> ...             bar2 += 1
> ...             print bar2
> ...     fee()
> ...
>>>> foo()
> 0
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "<stdin>", line 8, in foo
>   File "<stdin>", line 6, in fee
> UnboundLocalError: local variable 'bar2' referenced before assignment
> 
> Is the bar in "print bar" the bar of foo(), or is it an unbound bar?

It's "the bar of foo" since the block of fee has no binding operations
on it so nested local scopes apply.

> Is foo.bar2 the bar2 in fee() or is it a new local fee.bar2? The traceback

The bar2 in fee is a local variable of bar2 because the body of fee
includes the binding operation "bar2 +=".

Actually, all augmented assignments can only ever *RE*-bind their LHS,
so the compiler might be able to diagnose the error if a block's only
binding operations on a name are augmented assignments -- in theory.

> implies that the "print bar" statement used foo.bar, yet it blew up on
> incrementing bar2! 

Yes, because bar comes from outer scope (since there is no binding
operation on it) but bar2 is a local (since there IS a binding op on it).

> (Note: the error reporting seems misleading, since "+="
> is an assignment no?)

It's an access, "perhaps" followed by an assignment (which is why it
can only ever re-bind, or alter -- never bind anew a name that was
not bound before...: because first it must access that name's present
binding).  The reference (access) is indeed before any assignment.


Alex




More information about the Python-list mailing list