[Python-Dev] global variable modification in functions [Re: elimination of scope bleeding of iteration variables]

Ben Wing ben at 666.com
Mon May 1 05:47:07 CEST 2006

Nick Coghlan wrote:

> Ben Wing wrote:
>> apologies if this has been brought up on python-dev already.
>> a suggestion i have, perhaps for python 3.0 since it may break some 
>> code (but imo it could go into 2.6 or 2.7 because the likely breakage 
>> would be very small, see below), is the elimination of the misfeature 
>> whereby the iteration variable used in for-loops, list 
>> comprehensions, etc. bleeds out into the surrounding scope.
>> [i'm aware that there is a similar proposal for python 3.0 for list 
>> comprehensions specifically, but that's not enough.]
> List comprehensions will be fixed in Py3k. However, the scoping of for 
> loop variables won't change, as the current behaviour is essential for 
> search loops that use a break statement to terminate the loop when the 
> item is found. Accordingly, there is plenty of code in the wild that 
> *would* break if the for loop variables were constrained to the for 
> loop, even if your own code wouldn't have such a problem.
> Outside pure scripts, significant control flow logic (like for loops) 
> should be avoided at module level. You are typically much better off 
> moving the logic inside a _main() function and invoking it at the end 
> of the module. This avoids the 'accidental global' problem for all of 
> the script-only variables, not only the ones that happen to be used as 
> for loop variables.

i did in fact end up doing that.  however, in the process i ran into 
another python annoyance i've tripped over repeatedly: you can't assign 
to a global variable without explicitly declaring it as `global'.  
instead, you "magically" get a shadowing local variable.  this behavior 
is extremely hostile to newcomers: e.g.

foo = 1

def set_foo():
  foo = 2

print foo

--> 1

the worst part is, not a single warning from Python about this.  in a 
large program, such a bug can be very tricky to track down.

now i can see how an argument against changing this behavior might hinge 
upon global names like `hash' and `list'; you certainly wouldn't want an 
intended local variable called `hash' or `list' to trounce upon these.  
but this argument confuses lexical and dynamic scope: global variables 
declared inside a module are (or can be viewed as) globally lexically 
scoped in the module, whereas `hash' and `list' are dynamically scoped.

so i'd suggest:

[1] ideally, change this behavior, either for 2.6 or 3.0.  maybe have a 
`local' keyword if you really want a new scope.
[2] until this change, python should always print a warning in this 
[3] the current 'UnboundLocal' exception should probably be more 
helpful, e.g. suggesting that you might need to use a `global foo' 


More information about the Python-Dev mailing list