Reputation: 4916
I was wrestling with a weird "UnboundLocalError: local variable referenced before assignment" issue in a multi-submodule project I am working on and slimmed it down to this snippet (using the logging module from standard library):
import logging
def foo():
logging.info('foo')
def bar():
logging.info('bar')
if False:
import logging.handlers
# With these alternatives things work:
# import logging.handlers as logginghandlers
# from logging.handlers import SocketHandler
logging.basicConfig(level=logging.INFO)
foo()
bar()
Which has this output (I tried python 2.7 and 3.3):
INFO:root:foo
Traceback (most recent call last):
File "import-test01.py", line 16, in <module>
bar()
File "import-test01.py", line 7, in bar
logging.info('bar')
UnboundLocalError: local variable 'logging' referenced before assignment
Apparently the presence of an import statement inside a function hides already existing variables with the same name in the function scope, even if the import is not executed.
This feels counter-intuitive and non-pythonic. I tried to find some information or documentation about this, without much success thus far. Has someone more information/insights about this behaviour?
thanks
Upvotes: 5
Views: 669
Reputation: 156278
The problem you're having is just a restatement of the same ol' way python deals with locals masking globals.
to understand it, import foo
is (approximately) syntactic sugar for:
foo = __import__("foo")
thus, your code is:
x = 1
def bar():
print x
if False:
x = 2
since the name logging
appears on the left side of an assignment statement inside bar, it is taken to be a local variable reference, and so python won't look for a global by the same name in that scope, even though the line that sets it can never be called.
The usual workarounds for dealing with globals apply: use another name, as you have found, or:
def bar():
global logging
logging.info('bar')
if False:
import logging.handlers
so that python won't think logging
is local.
Upvotes: 4
Reputation: 9359
By that import
statement you introduce logging
as a local variable in the function and you call that local variable before it's initialized.
def bar():
import logging.handlers
print locals()
>>> foo()
{'logging': <module 'logging' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/logging/__init__.pyc'>}
Upvotes: 1