在调试问题的过程中,我将有问题的程序简化为几行,但我仍然不明白什么是错的。你能帮忙吗?
import logging
def setup():
logging.warning("start")
import logging.handlers
setup()
上面的代码会产生异常:
logging.warning( “开始”)
UnboundLocalError:在赋值之前引用的局部变量'logging'
和pylint抱怨:
W:5,4:从外部范围重新定义名称'logging'(第1行) (重新定义-外名)
这种修改似乎有所帮助,但我不知道为什么:
import logging.handlers as lh
请注意,在执行第二个import语句之前抛出异常。我很困惑。
答案 0 :(得分:2)
logging.warning
函数将尝试首先在setup()
函数中引用来自本地范围的变量,该函数来自import logging.handlers
,它会发现它是在您行之后声明的使用它。
尝试将其更改为:
import logging
def setup():
global logging
logging.warning("start")
import logging.handlers
setup()
答案 1 :(得分:2)
如果您反汇编该函数的字节码,则可以看到问题:
>>> dis.dis(setup) 2 0 LOAD_FAST 0 (logging) 3 LOAD_ATTR 0 (warning) 6 LOAD_CONST 1 ('start') 9 CALL_FUNCTION 1 (1 positional, 0 keyword pair) 12 POP_TOP 3 13 LOAD_CONST 2 (0) 16 LOAD_CONST 0 (None) 19 IMPORT_NAME 1 (logging.handlers) 22 STORE_FAST 0 (logging) 25 LOAD_CONST 0 (None) 28 RETURN_VALUE
请注意代码如何导入名称logging.handlers
,然后将模块对象指定为名称logging
。
所以基本上就像你的功能是:
def setup():
logging.warning('start')
logging = __import__('logging.handlers')
或者,删除导入机制:
x = 0
def setup():
# inside this function *all* x refer to the same object
print(x)
x = 1
请记住,给定范围内的名称只能引用一个对象。通过赋值,编译器将logging
解释为整个范围的本地变量,这是完整的函数体,从而调用{{1}产生warning
因为UnboundLocalError
的分配是在之后完成的。
您应该将导入作为函数中的第一个语句移动,或者只是将其移动到全局范围内(这是执行此操作的首选方法)。
如果要强制编译器引用全局变量,则必须通过添加logging
/ global logging
语句告诉他。在这种情况下,不会创建局部变量,但会使用全局变量。