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
创建一个局部变量?!我一点也没想到。但是你是对的,它在文档中。谢谢你的详细回答。如果可以的话,我会接受两者。谢谢你详细的回答。如果可以的话,我会两者都接受。