##Python import 遇到的几个问题
python 作为一个脚本语言,具有很多优良的特性,笔者最喜欢的大概是他丰富的函数库,同时在工作中自己也会开发一些库来使用,这样就会经常用到 import 功能。譬如我们有如下两个文件:1
2#bar.py
bar_var=1
1 | #foo.py |
在 foo.py 中我们引入了 bar 中的 bar_var 的变量。下面我们介绍 python 引用的机制及常见的问题。
Python import 机制
python 在执行import 的时候实际上是将引入的文件执行了一遍,并将对应文件加入了 module 列表中,我们对 foo.py 文件做如下修改:
1 | #foo.py |
运行后出现如下结果:
1 | ➜ Python python foo.py |
我们可以看到,在引入 bar模块之前在模块列表中是没有这个模块的,引用之后就在模块列表中增加了对应的模块名称。
Python 为了解决循环引用的问题,只要在程序中引用过,之后不会再次引用。我们对 foo.py 文件和 bar.py 文件修改如下:1
2
3#bar.py
print "impoted"
bar_var=1
1 | #foo.py |
执行结果如下:1
2➜ Python python foo.py
impoted
Python import 问题
如果我们将两个文件互相引用会出现什么问题呢?例如 bar.py 和 foo.py 文件如下:1
2
3#bar.py
from foo import foo_var
bar_var=1
1 | #foo.py |
如果运行 foo.py 文件会报错如下:1
2
3
4
5
6
7
8
9➜ Python python foo.py
Traceback (most recent call last):
File "foo.py", line 2, in <module>
from bar import bar_var
File "/Users/simon/Development/Python/bar.py", line 2, in <module>
from foo import foo_var
File "/Users/simon/Development/Python/foo.py", line 2, in <module>
from bar import bar_var
ImportError: cannot import name bar_var
通过异常链我们可以看到在执行 python foo.py 文件的时候程序的运行过程,包括以下几步:
- foo.py 文件执行到第2行发现需要引用 bar 模块,
- 查找 sys.modules 字典发现没有引入对应的模块,则引入 bar.py 文件,并添加到 sys.modules
- bar.py 文件被引入后执行到第2行发现需要引用 foo 模块
- 查找 sys.modules 字典发现没有引入对应的模块,则引入 foo.py 文件
- foo.py 文件被引入后执行到第2行发现需要引用 bar 模块
- 查找 sys.modules 字典发现已经引入了 bar 模块,则直接将bar 模块中的 bar_var 赋值给当前正在引入的 foo.py 文件
- 已经引入的 bar 模块还没有执行到第三行,因此没有 bar_var 这个变量的值,赋值失败,报错
如果将文件内容修改为如下代码,则不会出错:1
2
3#bar.py
bar_var=1
from foo import foo_var
1 | #foo.py |
运行结果如下:1
2➜ Python python foo.py
➜ Python
运行流程如下:
- foo.py 文件执行到第2行发现需要引用 bar 模块,
- 查找 sys.modules 字典发现没有引入对应的模块,则引入 bar.py 文件,并添加到 sys.modules
- bar.py 文件被引入后执行到第3行发现需要引用 foo 模块
- 查找 sys.modules 字典发现没有引入对应的模块,则引入 foo.py 文件
- foo.py 文件被引入后执行到第2行发现需要引用 bar 模块
- 查找 sys.modules 字典发现已经引入了 bar 模块,则直接将bar 模块中的 bar_var 赋值给当前正在引入的 foo.py 文件
- bar 模块中已经执行到了第3行,已经对 bar_var 变量进行了赋值,foo 模块成功引入了 bar_var
- foo模块执行到第3行对 foo_var 进行赋值,返回 bar模块
- 返回 foo.py 文件