python – What does from __future__ import absolute_import actually do?

python – What does from __future__ import absolute_import actually do?

The changelog is sloppily worded. from __future__ import absolute_import does not care about whether something is part of the standard library, and import string will not always give you the standard-library module with absolute imports on.

from __future__ import absolute_import means that if you import string, Python will always look for a top-level string module, rather than current_package.string. However, it does not affect the logic Python uses to decide what file is the string module. When you do

python pkg/script.py

pkg/script.py doesnt look like part of a package to Python. Following the normal procedures, the pkg directory is added to the path, and all .py files in the pkg directory look like top-level modules. import string finds pkg/string.py not because its doing a relative import, but because pkg/string.py appears to be the top-level module string. The fact that this isnt the standard-library string module doesnt come up.

To run the file as part of the pkg package, you could do

python -m pkg.script

In this case, the pkg directory will not be added to the path. However, the current directory will be added to the path.

You can also add some boilerplate to pkg/script.py to make Python treat it as part of the pkg package even when run as a file:

if __name__ == __main__ and __package__ is None:
    __package__ = pkg

However, this wont affect sys.path. Youll need some additional handling to remove the pkg directory from the path, and if pkgs parent directory isnt on the path, youll need to stick that on the path too.

The difference between absolute and relative imports come into play only when you import a module from a package and that module imports an other submodule from that package. See the difference:

$ 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
>>> 

In particular:

$ 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

Note that python2 pkg/main2.py has a different behaviour then launching python2 and then importing pkg.main2 (which is equivalent to using the -m switch).

If you ever want to run a submodule of a package always use the -m switch which prevents the interpreter for chaining the sys.path list and correctly handles the semantics of the submodule.

Also, I much prefer using explicit relative imports for package submodules since they provide more semantics and better error messages in case of failure.

python – What does from __future__ import absolute_import actually do?

Leave a Reply

Your email address will not be published.