import logging.handlers 破坏了我的程序。为什么?
import logging.handlers breaks my program. Why?
在调试问题时,我已经将有问题的程序简化为只有几行,但我仍然不明白哪里出了问题。你能帮忙吗?
import logging
def setup():
logging.warning("start")
import logging.handlers
setup()
上面的代码产生了一个异常:
logging.warning("start")
UnboundLocalError: local variable 'logging' referenced before assignment
并且 pylint 抱怨:
W: 5, 4: Redefining name 'logging' from outer scope (line 1)
(redefined-outer-name)
这个修改似乎有帮助,但我不知道为什么:
import logging.handlers as lh
请注意,异常是在执行第二个导入语句之前抛出的。我很困惑。
logging.warning
函数将首先尝试在 setup()
函数中引用局部作用域的变量,该函数来自 import logging.handlers
,它发现它在你的行之后声明正在使用它。
尝试将其更改为:
import logging
def setup():
global logging
logging.warning("start")
import logging.handlers
setup()
如果反汇编该函数的字节码,您会发现问题所在:
>>> 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
解释为整个范围的 local 变量 ,这是完整的函数体 ,因此调用 warning
会产生一个 UnboundLocalError
,因为对 logging
的赋值是在之后完成的。
您应该将导入作为函数中的第一条语句移动,或者只是将其移动到全局范围内(这是执行此操作的首选方式)。
如果你想强制编译器引用全局变量,你必须通过添加 global logging
/global x
语句来告诉他。在这种情况下,不会创建局部变量,但会使用全局变量。
在调试问题时,我已经将有问题的程序简化为只有几行,但我仍然不明白哪里出了问题。你能帮忙吗?
import logging
def setup():
logging.warning("start")
import logging.handlers
setup()
上面的代码产生了一个异常:
logging.warning("start")
UnboundLocalError: local variable 'logging' referenced before assignment
并且 pylint 抱怨:
W: 5, 4: Redefining name 'logging' from outer scope (line 1) (redefined-outer-name)
这个修改似乎有帮助,但我不知道为什么:
import logging.handlers as lh
请注意,异常是在执行第二个导入语句之前抛出的。我很困惑。
logging.warning
函数将首先尝试在 setup()
函数中引用局部作用域的变量,该函数来自 import logging.handlers
,它发现它在你的行之后声明正在使用它。
尝试将其更改为:
import logging
def setup():
global logging
logging.warning("start")
import logging.handlers
setup()
如果反汇编该函数的字节码,您会发现问题所在:
>>> 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
解释为整个范围的 local 变量 ,这是完整的函数体 ,因此调用 warning
会产生一个 UnboundLocalError
,因为对 logging
的赋值是在之后完成的。
您应该将导入作为函数中的第一条语句移动,或者只是将其移动到全局范围内(这是执行此操作的首选方式)。
如果你想强制编译器引用全局变量,你必须通过添加 global logging
/global x
语句来告诉他。在这种情况下,不会创建局部变量,但会使用全局变量。