关于python:困惑为什么导入os; os.environ [‘a’] =’x’; import os.path引发UnboundLocalError

Confused why import os; os.environ['a'] = 'x'; import os.path raises UnboundLocalError

有人能解释为什么会发生以下情况? 我看看我应该使用`import os.path`还是`import os`? 这是内容丰富,模糊相似,但并没有真正为我澄清。

如果我注释掉import os.path或在import os之后直接添加它,则没有错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ python -V
Python 2.7.2
$ cat min.py
import os

def main():
    os.environ['blah'] = 'bloo'
    import os.path


if __name__ == '__main__':
    main()
$ python min.py
Traceback (most recent call last):
  File"min.py", line 9, in <module>
    main()
  File"min.py", line 4, in main
    os.environ['blah'] = 'bloo'
UnboundLocalError: local variable 'os' referenced before assignment
$


因为导入也是一项任务。如果在main方法中执行import os.path,则表示os是本地名称,而Python不会在全局范围内查看您已导入的os


1
2
3
4
5
6
7
# assigns 'os' to global namespace
import os

def main():
    os.environ['blah'] = 'bloo' # <== which 'os'?  python assumes local
    # assigns 'os' to local namespace
    import os.path

import做两件事。首先,它创建一个模块对象。其次,它为新创建的模块对象命名。赋予名称的是赋值,因此错误消息"UnboundLocalError: local variable 'os' referenced before assignment"。

Python有关于名称可见性以及何时可以引用它们的规则。其中一条规则是,函数中是否存在歧义,无论您是指要引用本地名称还是全局名称。如果在与全局名称相同的函数内的任何位置创建本地名称,则Python假定函数内对该名称的所有引用都引用本地名称(除非您另有说明)。

三个可能的修复。

删除本地导入:

1
2
3
4
import os

def main():
    os.environ['blah'] = 'bloo'

删除全局导入并将本地导入移动到函数顶部

1
2
3
def main():
    import os.path
    os.environ['blah'] = 'bloo'

在函数开头声明os global,以便第一个引用使用全局:

1
2
3
4
5
6
import os

def main():
    global os
    os.environ['blah'] = 'bloo'
    import os.path

关于进口的说明。

1
2
3
4
5
6
7
8
9
# has the same effect as 'import module'
# creates a reference named 'module'
import module.submodule

# imports submodule and creates a reference to it named 'submodule'
from module import submodule

# imports submodule and creates a reference to it named 'x'
import module.submodule as x


我之所以发生这种情况,是因为您在导入之前尝试使用库'os'。
你可以做

1
2
3
4
5
6
7
8
9
def main():
    import os
    #now you can use os.environment
    os.environ['blah'] = 'bloo'
    #you don't need to import os.path as os is already imported


if __name__ == '__main__':
    main()