confusing UnboundLocalError behaive

Steven D'Aprano steven at REMOVE.THIS.cybersource.com.au
Mon Feb 23 04:02:46 EST 2009


On Mon, 23 Feb 2009 00:06:58 -0800, neoedmund wrote:

> see the 3 small piece of code, i cannot understand why it result as
> this.
> 
> 1.
> def test():
> 	abc="111"
> 	def m1():
> 		print(abc)
> 	m1()
> test()
> 
> Output: 111

abc is local to test(). print(abc) looks for a local abc, can't find one, 
and so searches the higher scope, and finds it there.



> 2.
> def test():
> 	abc="111"
> 	def m1():
> 		print(abc)
> 		abc+="222"
> 	m1()
> test()
> 
> Output:
>    print(abc)
> UnboundLocalError: local variable 'abc' referenced before assignment


Because you make an assignment to abc inside the m1() function, but 
didn't declare it as global, Python assumes that it must be a local 
variable. So when you try to print it, it doesn't have a value yet.

Solution: don't do that, or use the statement nonlocal (like global, 
except I think it is only introduced in Python 3.0).

 
> 3.
> def test2():
> 	abc=[111]
> 	def m1():
> 		print(abc)
> 		abc.append(222)
> 	m1()
> 	print(abc)
> test2()
> 
> Output:
> [111]
> [111,222]
> 
> it seems "you cannot change the outter scope values but can use it
> readonly."

But you're not using it read-only, because the append worked.

What you can't do is assign to the name.


Have a look at the disassembled code:

>>> import dis
>>> def spam():
...     print x
...     y = x+1
...
>>> dis.dis(spam)
  2           0 LOAD_GLOBAL              0 (x)
              3 PRINT_ITEM
              4 PRINT_NEWLINE

  3           5 LOAD_GLOBAL              0 (x)
              8 LOAD_CONST               1 (1)
             11 BINARY_ADD
             12 STORE_FAST               0 (y)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE
>>>
>>> def ham():
...     print x
...     x = x+1
...
>>> dis.dis(ham)
  2           0 LOAD_FAST                0 (x)
              3 PRINT_ITEM
              4 PRINT_NEWLINE

  3           5 LOAD_FAST                0 (x)
              8 LOAD_CONST               1 (1)
             11 BINARY_ADD
             12 STORE_FAST               0 (x)
             15 LOAD_CONST               0 (None)
             18 RETURN_VALUE



-- 
Steven



More information about the Python-list mailing list