Relative imports for the billionth time
Relative imports are a facet of Python that can powerfully simplify your project's organization by relying on the hierarchy of directories within a package. By adding an __init__.py
file, your directory blooms into a package. Use dot notation for your imports—.
references the current directory, while ..
indicates the parent directory. If you want to import module.py
from a companion package:
Don't forget to launch your script as a module to preserve the hierarchical structure. Use -m
for this:
Instead of calling scripts with relative imports directly (i.e., python myscript.py
), maintain the script as a main module to ensure the package structure is upheld and relative paths are properly resolved.
Navigating up and down the hierarchy
Running scripts with the -m
switch is akin to getting access to the entire blueprint of your package structure. When used, Python preserves the hierarchical context of your imports, allowing relative imports to function properly.
Scripts that form the entry point of your application should, ideally, reside outside your package directory structure. Utilize absolute imports to load the necessary modules and avoid the dreaded ImportError
due to misplaced relative imports.
Python needs to find your package in sys.path
to successfully import it. In certain scenarios (unit tests or deployment scripts), you may need to add your package directory to sys.path
explicitly. But wield this power sparingly—dynamically changing sys.path
can lead to cryptic bugs.
When working in interactive shells or REPL, remember that these are treated as __main__
and lack a package context. Avert the relative import path and use absolute imports.
When __main__
isn't so mean
It's important to note that scripts executed as __main__
can't use relative imports. If you want to use modules as scripts and still keep them importable, put your executable code under if __name__ == '__main__':
like it's your secret code stash.
While this can be helpful, for a stable and readable codebase, prefer absolute imports when possible.
Ironing out misconceptions and common issues
There might be a few rough edges when you first start with relative imports:
- Package Formalities: Do not forget to dress your directories with an
__init__.py
file in order to be accepted in the Python package party. - Avoid Manipulating sys.path: Delve into the world of
sys.path
only when you really need to. It’s not the magic “fix my imports” button. - Absolute Imports Are Absolute: When possible, try to use absolute imports. They present a clear portrayal of your package layout and are less prone to errors compared to their relative counterparts.
- Running Modules: If you may recall, the
-m
switch is your ally to keep the package context intact.
Navigating through potential issues
At times, you might get a ModuleNotFoundError
or ImportError
when the Python interpreter can't place your module within a package. This is similar to forgetting your address when ordering hamburgers online—a classic facepalm moment.
Consider these tips to avoid such a predicament:
- Always run modules using the
-m
switch. - Keep the
__init__.py
files in every directory of your package. - Make sure you are in the right place by checking the current working directory and
sys.path
. - When using scripts as entry points and referring to your package modules, stick with absolute imports.
Was this article helpful?