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