Python import logging.handlers会中断我的程序。为什么?
在调试一个问题时,我已经将相关程序简化为几行,但我仍然不明白哪里出了问题。你能帮忙吗Python import logging.handlers会中断我的程序。为什么?,python,python-import,Python,Python Import,在调试一个问题时,我已经将相关程序简化为几行,但我仍然不明白哪里出了问题。你能帮忙吗 import logging def setup(): logging.warning("start") import logging.handlers setup() 上面的代码生成一个异常: 日志记录。警告(“开始”) UnboundLocalError:分配前引用的局部变量“logging” 派林抱怨说: W:5,4:从外部范围(第1行)重新定义名称“日志记录” (重新定义外部名称)
import logging
def setup():
logging.warning("start")
import logging.handlers
setup()
上面的代码生成一个异常:
日志记录。警告(“开始”)
UnboundLocalError:分配前引用的局部变量“logging”
派林抱怨说:
W:5,4:从外部范围(第1行)重新定义名称“日志记录”
(重新定义外部名称)
这一修改似乎有所帮助,但我不知道为什么:
import logging.handlers as lh
请注意,在执行第二条导入语句之前会引发异常。我很困惑。日志记录。警告
函数将尝试首先在设置()
函数中引用本地作用域中的变量,该函数来自导入日志记录。处理程序
,它会在您使用它的行之后声明它
尝试将其更改为:
import logging
def setup():
global logging
logging.warning("start")
import logging.handlers
setup()
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
或者,删除导入机制:
x = 0
def setup():
# inside this function *all* x refer to the same object
print(x)
x = 1
请记住,给定范围中的名称只能引用一个对象。通过赋值,编译器将整个作用域的logging
解释为局部变量,该作用域是完整的函数体,因此调用warning
会产生UnboundLocalError
,因为对logging
的赋值是在之后完成的
您应该将导入作为函数中的第一条语句移动,或者只在全局范围内移动它(这是执行此操作的首选方式)
如果要强制编译器引用全局变量,必须通过添加global logging
/global x
语句来告诉编译器。在这种情况下,不会创建局部变量,但会使用全局变量。如果您为该函数反汇编字节码,则可以看到问题:
>>> 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
或者,删除导入机制:
x = 0
def setup():
# inside this function *all* x refer to the same object
print(x)
x = 1
请记住,给定范围中的名称只能引用一个对象。通过赋值,编译器将整个作用域的logging
解释为局部变量,该作用域是完整的函数体,因此调用warning
会产生UnboundLocalError
,因为对logging
的赋值是在之后完成的
您应该将导入作为函数中的第一条语句移动,或者只在全局范围内移动它(这是执行此操作的首选方式)
如果要强制编译器引用全局变量,必须通过添加global logging
/global x
语句来告诉编译器。在这种情况下,不会创建局部变量,但会使用全局变量。这是将所有导入置于全局范围的原因之一。导入logging.handlers
的成本并不高,您可以通过将启动时间推迟到调用setup
来提高启动时间。您有一种误解,即在python中,范围是从定义开始的,而事实并非如此。Python具有块作用域,因此在def()中:print(x);x=1
两次出现的x
都引用了同一个局部变量,您会得到一个错误,因为您在初始化它之前引用了该局部变量。@chepner:日志记录。仅当设置了特定选项时,才会有条件地导入和使用处理程序。我已经删除了这个和其他无关的代码。这是将所有导入放在全局范围的原因之一。导入logging.handlers
的成本并不高,您可以通过将启动时间推迟到调用setup
来提高启动时间。您有一种误解,即在python中,范围是从定义开始的,而事实并非如此。Python具有块作用域,因此在def()中:print(x);x=1
两次出现的x
都引用了同一个局部变量,您会得到一个错误,因为您在初始化它之前引用了该局部变量。@chepner:日志记录。仅当设置了特定选项时,才会有条件地导入和使用处理程序。我已经删除了这个和其他无关的代码。import
创建了一个局部变量?!我一点也没想到。但是你是对的,它在文档中。import
创建一个局部变量?!我一点也没想到。但是你是对的,它在文档中。谢谢你的详细回答。如果可以的话,我会接受两者。谢谢你详细的回答。如果可以的话,我会两者都接受。