In the PyTexas Discord my fellow PyTexas organizer and friend, Mason Egger, asked:
Do you prefer absolute or relative imports for inter-module imports within applications?
Go ahead and call me a Sith because I deal in absolutes.
And here’s why.
Ways of running Python files #
Python has more than a few ways of running a “Python file”:
python path/to/file.py
: Run the file at this pathpython -m path.to.file
: Run the module found with this dotted namepython path/to
: Run the__main__.py
file under this directory pathpython -m path/to
: Run the module found with this dotted name, which this time would be the directory’s__init__.py
python path/to/zipapp.zip
: Run this zipapppytest
or any other installed script name: Run the script found at<Python environment directory>/bin/<name>
, e.g..venv/bin/pytest
Ways of importing your fellow module #
from . import sibling
: Importssibling
from under the same/parent directory this module is in- This first would try to import attribute
sibling
from__init__.py
- then try to import the module named
sibling
(eithersibling/__init__.py
orsibling.py
)
- This first would try to import attribute
from .sibling import boogers
: Same idea, but this time we need to load modulesibling
and attribute/submoduleboogers
from .. import uncle
: Importsuncle
from under the grandparent directory (using similar rules)from ..uncle import tickles
: (you get the jist)from ... import great_aunt
: …
These are all examples of relative imports. What they import is relative to the module importing them.
(By the way, in case you needed one, here’s an example of an absolute import: from pkgname.child import fun
)
Ways of running Python files which import their fellow modules #
Given this flat layout project:
.
├── macaroni/
│ ├── __init__.py
│ ├── salad.py
│ └── and_/
│ ├── __init__.py
│ └── cheese.py
Contents / Invocation | python -m macaroni.and_.cheese |
python macaroni/and_/cheese.py |
---|---|---|
from ..salad import dressing |
🎉 | 💥 ImportError: attempted relative import with no known parent package |
from macaroni.salad import dressing |
🎉 | 🎉 |
Why is that? #
Buried in the Python docs’ tutorials, in Chapter 6 “Modules”, Section 4 “Packages”, Subsection 2 “Intra-package References” (6.4.2. here), there is this paragraph 1:
Note that relative imports are based on the name of the current module’s package. Since the main module does not have a package, modules intended for use as the main module of a Python application must always use absolute imports.
When Python encounters a relative import, it is relative to the current package, which for the “main module” (the module being invoked), doesn’t exist.
The bottom line: Absolute imports work consistently irrespective of how your Python file is executed. Relative imports don’t give you that luxury.