classification
Title: UnboundLocalError in nested function
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 2.6, Python 2.5
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Andreas Hofmeister, mark.dickinson
Priority: normal Keywords:

Created on 2010-06-21 19:46 by Andreas Hofmeister, last changed 2010-06-22 08:26 by mark.dickinson. This issue is now closed.

Messages (4)
msg108306 - (view) Author: Andreas Hofmeister (Andreas Hofmeister) Date: 2010-06-21 19:46
Description:
An unexpected UnboundLocalError is produced when assigning a value to a variable inside a nested function. The first assignment to the variable is in the enclosing function.

Example:
def x():
     a = False
     def y():
         print a
         a = True
     return y

Calling x()() produces an UnboundLocalError on the 'print a' line.
If the 'a = True' line is removed, no error occurs.

Tested with:
  - 2.5.1
  - 2.6.5

Keywords: 
Nested function, UnboundLocalError, variable assignment

Thank you for your attention
msg108309 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-06-21 19:52
This isn't a bug;  it's by design.

Because there's an assignment to 'a' in the function 'y', 'a' is considered local to that function.  (It doesn't matter where the assignment happens within the function;  the presence of an assignment anywhere is enough to make 'a' local for the entirety of 'y'.)

This is described in the reference manual at:

http://docs.python.org/reference/executionmodel.html#naming-and-binding

See the paragraph beginning:

"If a name binding operation occurs anywhere within a code block, "
msg108337 - (view) Author: Andreas Hofmeister (Andreas Hofmeister) Date: 2010-06-22 05:11
Thank you for your assistance. I apologize for not examining the reference manual closely. 
Is there any way to produce the desired behavior? I currently work around the local name binding like this:

def x():
     a = [False]
     def y():
         print a[0]
         a[0] = True
     return y

However, using a list here seems awkward.
Thank you for your attention.
msg108345 - (view) Author: Mark Dickinson (mark.dickinson) * (Python committer) Date: 2010-06-22 08:26
> Is there any way to produce the desired behavior?

Not directly, in Python 2.x.  (But there's the 'nonlocal' keyword in 3.x.)  There are various workarounds, but what's best depends on what you're doing.  The python-list mailing list is probably a better place to get answers.
History
Date User Action Args
2010-06-22 08:26:14mark.dickinsonsetmessages: + msg108345
2010-06-22 05:11:16Andreas Hofmeistersetmessages: + msg108337
2010-06-21 19:55:05eric.araujosetstage: resolved
2010-06-21 19:52:40mark.dickinsonsetstatus: open -> closed

nosy: + mark.dickinson
messages: + msg108309

resolution: not a bug
2010-06-21 19:46:37Andreas Hofmeistercreate