import logging.handlers打破了我的程序。为什么?

时间:2016-07-31 16:06:49

标签: python python-import

在调试问题的过程中,我将有问题的程序简化为几行,但我仍然不明白什么是错的。你能帮忙吗?

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语句之前抛出异常。我很困惑。

2 个答案:

答案 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语句告诉他。在这种情况下,不会创建局部变量,但会使用全局变量。