在函数内部导入模块时为什么会出现UnboundLocalError错误

3
由于某种原因,此代码会产生错误:
import os

def main():
    print(os.path.isfile('/bin/cat'))
    import os

if __name__ == '__main__':
    main()

结果:

Traceback (most recent call last):
  File "test.py", line 10, in <module>
    main()
  File "test.py", line 5, in main
    print(os.path.isfile('/bin/cat'))
UnboundLocalError: local variable 'os' referenced before assignment


为什么会发生这种情况?请注意,在这两种情况的开头都有import os。不知何故,在函数体末尾进行额外的导入会影响整个函数作用域。
如果在函数内部删除导入,一切正常(这并不奇怪)。
import os

def main():
    print(os.path.isfile('/bin/cat'))
    # import os

if __name__ == '__main__':
    main()

结果:

True

关于可能的重复问题:有一些类似的问题,但是与全局变量相关,而不是导入。


2
如果你在全局作用域中导入 os,那么你就创建了一个名为 os 的全局变量。如果你在局部作用域中导入 os,则会创建一个名为 os 的局部变量。如果你尝试在函数中使用一个在它被创建之前的局部变量,你会得到一个错误。 - khelwood
1个回答

1
如果你在全局作用域中导入 os 模块,那么你就创建了一个名为 os 的全局变量。如果你在局部作用域中导入 os 模块,那么你就创建了一个名为 os 的局部变量。如果你在函数中使用尚未创建的局部变量,你会得到错误提示。这和显式赋值变量时出现的错误一样。
同样的解决方法也适用于想要在函数内导入模块并创建一个全局变量的情况,你可以使用 global 关键字。
def main():
    global os
    print(os.path.isfile('/bin/cat'))
    import os

或者您可以更改本地导入以使用不同的变量名称,以使您对 os 的使用无歧义。

def main():
    print(os.path.isfile('/bin/cat'))
    import os as _os

尽管这只是一个演示示例,但在这种情况下,没有必要在您已经全局导入了os的情况下再在函数内重新导入它。

请注意,这两个示例中我都在开头执行了 import os。但我仍然不明白为什么在函数开头的某行额外导入会导致错误。 - dankal444
1
因为如果你在函数内创建了一个名为os的变量(使用import os),那么解释器会将函数中所有对os名称的引用视为局部变量而不是全局变量。这与关于在函数中使用全局变量的其他问题完全相同。 - khelwood
好的,那么在函数内定义变量会覆盖整个函数作用域,而不仅仅是在该定义之后的行吗?如果是这样,那就是我缺少的东西。 - dankal444
由于您的问题中提到“有一些类似的问题,但是涉及全局变量而不是导入”,我认为您可能已经了解了这一部分,因为所有这些重复的问题都是关于这个的。 - khelwood
全局变量与导入有一些不同。它们共享很多相似之处,但例如你不需要像全局变量一样在每个函数的开头指定导入内容。我仍然不知道为什么会这样,但我认为这是另一个问题的材料。 - dankal444

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接