有条件的本地导入例外

时间:2019-01-18 12:34:36

标签: python

考虑代码段

import something
import sys
print(sys.version)

def f(a):
    b = a
    if a==1:
        import something
    b *= something.value # <<<<<
    return b

print(f(1))
print(f(2))

其中模块something定义value = 1。使用Python 3.6.7运行该脚本,调用f(1)成功,但调用f(2)失败,但有一个例外:

UnboundLocalError: local variable 'something' referenced before assignment

在标记为<<<<<的行中。我真的不明白。我在Python 2.7中发现了同样的问题,所以我敢打赌这不是简单的回归,而是与Python处理此类本地导入的方式紧密相关。我在文档中找不到任何提示。有人解释吗?

2 个答案:

答案 0 :(得分:7)

import x语句有两件事*

  1. 如果尚未引用,它将加载(并运行)被引用的模块
  2. 它将模块分配给同名变量

您的函数仅在something时将模块something分配给变量 a == 1。如果为a != 1,则即使已加载模块,也未将其分配给变量,因此无法对其进行引用。

这就是为什么您的操作失败。这也是为什么您试图做的事情绝对没有优势的原因,因为模块仅在首次导入时才加载并运行。随后的所有时间都只是在执行步骤2。

您的代码未引用全局something的原因是因为python会覆盖全局名称,即使相同名称的局部变量出现在函数中的任何位置,即使从未到达也是如此。以下功能f与您的功能类似。

x = 1
def f(y):
    if False:
       x = y
    return x

解决方案是不要同时使用x作为局部变量和全局变量。

答案 1 :(得分:2)

如果在给定范围内分配了变量,则该变量在该范围内是本地的。如果该分配是有条件的,并且您可以运行代码(例如它永远不会发生)(或在分配给它之后在该作用域中被引用),则您将得到此异常。相同的较小示例:

def f():
    if False:
        a = 1
    print(a)

a = 1
f()

还有强制性的FAQ link