Variable scoping rules in Python?

Bruno Desthuilliers bruno.42.desthuilliers at wtf.websiteburo.oops.com
Mon Oct 8 11:06:44 EDT 2007


joshua.davies at travelocity.com a écrit :
> Ok, I'm relatively new to Python (coming from C, C++ and Java).  I'm
> working on a program that outputs text that may be arbitrarily long,
> but should still line up, so I want to split the output on a specific
> column boundary.

FWIW :
http://docs.python.org/lib/module-textwrap.html


>  Since I might want to change the length of a column,
> I tried defining the column as a constant (what I would have made a
> "#define" in C, or a "static final" in Java).  I defined this at the
> top level (not within a def), and I reference it inside a function.
> Like this:
> 
> COLUMNS = 80
> 
> def doSomethindAndOutputIt( ):
>   ...
>   for i in range( 0, ( len( output[0] ) / COLUMNS ) ):
>     print output[0][ i * COLUMNS : i * COLUMNS + ( COLUMNS - 1 ) ]
>     print output[1][ i * COLUMNS : i * COLUMNS + ( COLUMNS - 1 ) ]
>     ..
> 
> etc. etc.  It works fine, and splits the output on the 80-column
> boundary just like I want.
> 
> Well, I decided that I wanted "COLUMNS = 0" to be a special "don't
> split anywhere" value, so I changed it to look like this:
> 
> COLUMNS = 80
> 
> def doSomethindAndOutputIt( ):
>   ...
>   if COLUMNS == 0:
>     COLUMNS = len( output[ 0 ] )
 >
>   for i in range( 0, ( len( output[0] ) / COLUMNS ) ):
>     print output[0][ i * COLUMNS : i * COLUMNS + ( COLUMNS - 1 ) ]
>     print output[1][ i * COLUMNS : i * COLUMNS + ( COLUMNS - 1 ) ]
>     ..

Since you don't want to modify a global (and even worse, a CONSTANT), 
the following code may be a bit cleaner:

def doSomethindAndOutputIt( ):
   ...
   if COLUMNS == 0:
      columns = len( output[ 0 ] )
   else:
      columns = COLUMNS
   for i in range( 0, ( len( output[0] ) / COLUMNS ) ):
      print output[0][ i * columns : i * columns + ( columns - 1 ) ]
   ..


> Now, when I run it, I get the following error:
> 
> Traceback (most recent call last):
>   File "Test.py", line 140, in ?
>     doSomethingAndOutput( input )
>   File "Test.py", line 123, in doSomethingAndOutput
>     if COLUMNS == 0:
> UnboundLocalError: local variable 'COLUMNS' referenced before
> assignment
> 
> I went back and re-read chapter 13 of "Learning Python", which talks
> about variable scoping rules, and I can't figure out why Python is
> saying this variable in Unbound.  It works if I insert:
> 
>   global COLUMNS
> 
> before the "if" statement... but I don't understand why.  Is the
> interpreter scanning my entire function definition before executing
> it, recognizing that I *might* assign COLUMNS to a value, and deciding
> that it's a local on that basis?

You name it. That's *exactly* what happens.




More information about the Python-list mailing list