What does from __future__ import absolute_import actually do?
我回答了一个关于python中绝对导入的问题,我认为我是通过阅读python2.5的changelog和附带的pep理解的。然而,在安装了python 2.5并试图创建一个正确使用
直接从上面链接的changelog,这个语句准确地总结了我对绝对导入更改的理解:
Let's say you have a package directory like this:
1
2
3
4 pkg/
pkg/__init__.py
pkg/main.py
pkg/string.pyThis defines a package named
pkg containing thepkg.main andpkg.string submodules.Consider the code in the main.py module. What happens if it executes the statement
import string ? In Python 2.4 and earlier, it will first look in the package's directory to perform a relative import, finds pkg/string.py, imports the contents of that file as thepkg.string module, and that module is bound to the name"string" in thepkg.main module's namespace.
所以我创建了这个精确的目录结构:
1 2 3 4 5 6 | $ ls -R .: pkg/ ./pkg: __init__.py main.py string.py |
1 2 | import string print string.ascii_uppercase |
正如预期的那样,使用python 2.5运行此命令会在使用
1 2 3 4 5 | $ python2.5 pkg/main.py Traceback (most recent call last): File"pkg/main.py", line 2, in <module> print string.ascii_uppercase AttributeError: 'module' object has no attribute 'ascii_uppercase' |
然而,在2.5的变更日志中,我们发现了这一点(重点增加):
In Python 2.5, you can switch
import 's behaviour to absolute imports using afrom __future__ import absolute_import directive. This absolute-import behaviour will become the default in a future version (probably Python 2.7). Once absolute imports are the default,import string will always find the standard library's version.
因此,我创建了
1 2 3 | from __future__ import absolute_import import string print string.ascii_uppercase |
不过,用python 2.5运行这个程序…使用
1 2 3 4 5 | $ python2.5 pkg/main2.py Traceback (most recent call last): File"pkg/main2.py", line 3, in <module> print string.ascii_uppercase AttributeError: 'module' object has no attribute 'ascii_uppercase' |
这与
1 2 3 4 5 6 7 8 9 10 11 | $ python2.7 pkg/main.py Traceback (most recent call last): File"pkg/main.py", line 2, in <module> print string.ascii_uppercase AttributeError: 'module' object has no attribute 'ascii_uppercase' $ python2.7 pkg/main2.py Traceback (most recent call last): File"pkg/main2.py", line 3, in <module> print string.ascii_uppercase AttributeError: 'module' object has no attribute 'ascii_uppercase' |
以及python 3.5,有或没有(假设两个文件中的
1 2 3 4 5 6 7 8 9 10 11 | $ python3.5 pkg/main.py Traceback (most recent call last): File"pkg/main.py", line 2, in <module> print(string.ascii_uppercase) AttributeError: module 'string' has no attribute 'ascii_uppercase' $ python3.5 pkg/main2.py Traceback (most recent call last): File"pkg/main2.py", line 3, in <module> print(string.ascii_uppercase) AttributeError: module 'string' has no attribute 'ascii_uppercase' |
我测试过其他的变化。我创建了一个空模块,名为
在我看来,这很容易通过以下内容来解释(这是从python 2文档中得到的,但在python 3的同一个文档中,此语句保持不变):
sys.path
(...)
As initialized upon program startup, the first item of this list,
path[0] , is the directory containing the script that was used to invoke the Python interpreter. If the script directory is not available (e.g. if the interpreter is invoked interactively or if the script is read from standard input),path[0] is the empty string, which directs Python to search modules in the current directory first.
那我错过了什么?为什么
这个变更日志措辞粗俗。
1 | python pkg/script.py |
对于python来说,
要将文件作为
1 | python -m pkg.script |
在这种情况下,不会将
您还可以在
1 2 | if __name__ == '__main__' and __package__ is None: __package__ = 'pkg' |
但是,这不会影响
只有从包中导入模块,并且该模块从包中导入其他子模块时,绝对导入和相对导入之间的差异才会发挥作用。请看区别:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | $ mkdir pkg $ touch pkg/__init__.py $ touch pkg/string.py $ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py $ python2 Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2 Type"help","copyright","credits" or"license" for more information. >>> import pkg.main1 Traceback (most recent call last): File"<stdin>", line 1, in <module> File"pkg/main1.py", line 1, in <module> import string;print(string.ascii_uppercase) AttributeError: 'module' object has no attribute 'ascii_uppercase' >>> $ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py $ python2 Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2 Type"help","copyright","credits" or"license" for more information. >>> import pkg.main2 ABCDEFGHIJKLMNOPQRSTUVWXYZ >>> |
特别地:
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ python2 pkg/main2.py Traceback (most recent call last): File"pkg/main2.py", line 1, in <module> from __future__ import absolute_import;import string;print(string.ascii_uppercase) AttributeError: 'module' object has no attribute 'ascii_uppercase' $ python2 Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2 Type"help","copyright","credits" or"license" for more information. >>> import pkg.main2 ABCDEFGHIJKLMNOPQRSTUVWXYZ >>> $ python2 -m pkg.main2 ABCDEFGHIJKLMNOPQRSTUVWXYZ |
注意,
如果要运行包的子模块,请始终使用
另外,我更喜欢对包子模块使用显式的相对导入,因为它们在失败时提供更多的语义和更好的错误消息。