为什么在函数中使用模块后重新导入会抛出异常?

Why does RE-importing after a module is used in a function throw an exception?

我在欺骗 python2.7 这里:

import time

def foo():
    print time.time()  # EXCEPTION THROWN HERE
    import time

...抛出异常:

UnboundLocalError: local variable 'time' referenced before assignment

如果我删除重新导入:

import time

def foo():
    print time.time()  # WORKS AS EXPECTED
    #import time

...一切正常。很明显,当调用该函数时,从函数开始执行的那一刻起,有关稍后导入的某些内容会影响局部变量 table,而不是从包含点开始:

import time

def foo():
    global time
    print time.time()  # WORKS AS EXPECTED
    import time

...很奇怪。

这是因为一位工程师在大型方法的顶部添加了对 time.time() 的调用,但没有看到它在函数中间导入(由一位工程师很久以前就走了。)我不是在寻找如何解决问题的指导 - 这很明显(而且还涉及追捕做这件事的人,提供必要的毒品打击。)

我很好奇这个机制,为什么这样做,以及我可以检查系统的哪些部分以查看它的运行情况。

问题与import无关。它只是关于全局变量和局部变量。请参阅这个最小示例:

x = 0

def access():
    print(x)

def shadow():
    print(x)
    x = 1

现在我们来拆解函数,看看字节码:

access()

 0 LOAD_GLOBAL              0 (print)
 3 LOAD_GLOBAL              1 (x)
 6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
 9 POP_TOP
10 LOAD_CONST               0 (None)
13 RETURN_VALUE

可以看到符号x作为全局变量被查找LOAD_GLOBAL 1 (x)

shadow()

 0 LOAD_GLOBAL              0 (print)
 3 LOAD_FAST                0 (x)
 6 CALL_FUNCTION            1 (1 positional, 0 keyword pair)
 9 POP_TOP

10 LOAD_CONST               1 (1)
13 STORE_FAST               0 (x)
16 LOAD_CONST               0 (None)
19 RETURN_VALUE

当您在函数体中重新定义变量 x 时,我们得到的是这个字节码:LOAD_FAST 0 (x)。所以它被当作一个局部变量查找,即使此时它还没有被定义。由于没有定义局部变量 x 但我们得到 UnboundLocalError aka local variable not defined.

在您的示例中,模块 time 是 global/local 变量。