UnboundLocalError on shadowed import

B

Brad Clements

I was going to file this as a bug in the tracker, but maybe it's not really
a bug. Poor Python code does what I consider to be unexpected. What's your
opinion?

With Python 2.3.2 (but also happens with 2.2)

An import within a function that shadows a global import can raise
UnboundLocalError. I think the real problem is that the the local 'import
sys' is seen as occuring after the use of sys within this function, even
though sys is imported in global scope.

import sys

def t():
sys.exit(0)
import sys
sys.exit(1)

if __name__ == "__main__":
t()

I noticed this when editing an existing module. After adding 'import sys' at
the global level and then using sys in the function (and not noticing that
this function imported sys locally below), I got the UnboundLocalError

python2.3 ~/temp/test.py
Traceback (most recent call last):
File "/home/bkc/temp/test.py", line 10, in ?
t()
File "/home/bkc/temp/test.py", line 4, in t
sys.exit(0)
UnboundLocalError: local variable 'sys' referenced before assignment

This is not much of an error. The local import is superfluous, and no one
would really write code this way. But should it raise an exception?
 
P

Peter Hansen

Brad said:
python2.3 ~/temp/test.py
Traceback (most recent call last):
File "/home/bkc/temp/test.py", line 10, in ?
t()
File "/home/bkc/temp/test.py", line 4, in t
sys.exit(0)
UnboundLocalError: local variable 'sys' referenced before assignment

This is not much of an error. The local import is superfluous, and no one
would really write code this way. But should it raise an exception?

It "has to" raise an exception. The use of "sys" inside the function
is local (because you assign to it, because "import sys" is effectively
an assignment). Locals are not handled quite the same as other names,
as you know -- they are turned into index lookups in a list instead of
hash lookups in a dictionary. The interpreter can't know that your use
of sys.exit(0) is supposed to refer to the global sys, because all uses
of "sys" are really just "local variable number 3" or something like
that inside the function.

Basically, "don't do that" is about the best you'll get, I think.

-Peter
 
V

vincent wehren

Peter said:
It "has to" raise an exception. The use of "sys" inside the function
is local (because you assign to it, because "import sys" is effectively
an assignment). Locals are not handled quite the same as other names,
as you know -- they are turned into index lookups in a list instead of
hash lookups in a dictionary. The interpreter can't know that your use
of sys.exit(0) is supposed to refer to the global sys, because all uses
of "sys" are really just "local variable number 3" or something like
that inside the function.

Basically, "don't do that" is about the best you'll get, I think.

Well, just for the sake of it, there still is the obvious option of
adding the line "global sys" before sys.exit(0) to tell the interpreter
to use the "globally imported sys".
 
P

Peter Hansen

vincent said:
Well, just for the sake of it, there still is the obvious option of
adding the line "global sys" before sys.exit(0) to tell the interpreter
to use the "globally imported sys".

Which basically amounts to "not doing that". ;-) You're right...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top