Python绝对导入

absolute_import 绝对导入


绝对导入,指从顶层用import直接导入模块,即(只)从sys.path中导入模块。 例如:

1
2
3
4
import sys
import os
import sys.path
import sys.path.join as path_join

import关键词的歧义?


之所以引入绝对导入,是因为python中的import关键词存在歧义。当import foo被定义时,用户根本无法得知foo这个模块是内置模块,第三方安装模块,还是用户当前包下的自定义模块。目前python2.7.x默认情况下是优先导入当前目录下的自定义模块,那么在有冲突的情况下,内置(第三方)模块foo怎么导入?

如果相反,默认情况下导入的是内置或者第三方安装模块,那么本地的foo模块可以通过间接导入from . import foo方式导入,从而解决这个问题。

因此,绝对导入的概念被引入。python2.7.x可以通过from __future__ import absolute_import改变import行为,强制import foo导入的是sys.path下的模块,并且本地模块(非sys.path下的模块)必须通过相对导入的方式进行导入。

举例说明


目录结构如下:

1
2
3
4
5
6
7
8
9
10
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py

当前的文件package.subpackage1.moduleX.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from __future__ import absolute_import # __future__必须在代码的第一行
#绝对导入
import os
import sys
#相对导入
from . import moduleY
from .moduleY import xxx
from ..subpackage2 import moduleZ
#错误的导入, 绝对导入只能导入sys.path中的模块
#moduleY只能以相对导入的方式进行导入
#import moduleY
def main():
print 'ok'
if __name__ == '__main__:
main()

ValueError: Attempted relative import in non-package


在上面的例子中,当试图直接运行python moduleX.py时会报如上错误。
当直接运行moduleX.py时,此文件被视为一个顶层的脚本而不是包。 而在一个顶层脚本里是不能进行相对引用的。

可以在package层添加test.py脚本进行测试,内容如下。

1
2
3
from package.subpackage1 import moduleY
moduleY.main()

此时,package整体作为一个包,包内就可以进行相对导入了。 最终目录结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
project/
test.py
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py

参考


PEP328