My answer was about absolute import in Python, which I thought I understood based on reading the Python 2.5 change log and the accompanying PEP . However, when installing Python 2.5 and trying to create an example of the correct use of from __future__ import absolute_import , I understand that everything is not so clear.
Directly from the above list of changes, this statement accurately summarized my understanding of the absolute import change:
Say you have a package directory as follows:
pkg/ pkg/__init__.py pkg/main.py pkg/string.py
Defines a package named pkg containing the submodules pkg.main and pkg.string .
Consider the code in the main.py module. What happens if it executes the import string statement? In Python 2.4 and earlier, it will first search the package directory for relative imports, find pkg / string.py, import the contents of this file as the pkg.string module, and this module is bound to the name "string" in the pkg.main module namespace pkg.main
So, I created this exact directory structure:
$ ls -R .: pkg/ ./pkg: __init__.py main.py string.py
__init__.py and string.py are empty. main.py contains the following code:
import string print string.ascii_uppercase
As expected, doing this with Python 2.5 completes with an AttributeError :
$ 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'
However, further in 2.5 changelog, we find this (emphasized by me):
In Python 2.5, you can switch import behavior to absolute import using the from __future__ import absolute_import directive. This absolute import behavior will default in a future version (possibly Python 2.7). When absolute imports are by default, import string will always look for a standard library version.
Thus, I created pkg/main2.py identical to main.py , but with an additional directive for future imports. Now it looks like this:
from __future__ import absolute_import import string print string.ascii_uppercase
Running this with Python 2.5, however ... using AttributeError :
$ 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'
This is quite categorically contrary to the assertion that import string will always find the version of std-lib with absolute import enabled. What else, despite the warning that absolute imports will become โnew by defaultโ, I ran into this problem using both Python 2.7 and without the __future__ directive:
$ 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'
as well as Python 3.5 with or without (provided that the print statement changes in both files):
$ 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'
I tested other variations of this. Instead of string.py I created an empty module - a directory called string containing only empty __init__.py - and instead of issuing import from main.py , I have cd 'd to pkg and start importing directly from REPL. None of these options (as well as their combination) changed the results above. I canโt come to terms with what I read about the __future__ directive and absolute import.
It seems to me that this is easily explained by the following (this is from Python 2 docs, but this statement remains unchanged in the same docs for Python 3):
sys.path
(...)
As initialized at program startup, the first element 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 accessible (for example, if the interpreter is invoked interactively or if the script is read from standard input), path[0] is an empty string that directs Python to search for modules in the current one first.
So what am I missing? Why __future__ operator apparently not do what it says, and what is the resolution of this contradiction between the two sections of the documentation, as well as between the described and actual behavior?