Explain Codes LogoExplain Codes Logo

Relative imports in Python 3

python
relative-imports
package-structure
import-strategy
Alex KataevbyAlex Kataev·Aug 28, 2024
TLDR

For Python 3, to apply relative imports effectively, it's crucial your scripts are housed within a package — a directory containing an __init__.py file.

Let's use this file structure as an example:

mypackage/
    __init__.py
    module1.py
    module2.py

To import module1 from module2, code it out like this:

from . import module1

When it comes to running your script, execute it as a module from the package's parent directory:

python -m mypackage.module2

Following this will make sure your relative imports are resolved smoothly.

Crafting package structures & addressing imports

Packages in Python are effectively directories housing an __init__.py file. These could be packed with modules (.py files), and sub-packages (directories likewise containing __init__.py files). Importing maneuvers within this structure can vary, but should inherently stick to Python's guidelines for organising modules and packages.

Making a package: Getting friendly with init.py

Include an __init__.py file in your directory to flag it as a Python package:

pack_your_code/ __init__.py got_code.py

In your got_code.py, use relative imports to access other modules in the same package.

Absolute imports to the rescue

Contrary to relative imports, absolute imports lay out the complete path to each module, enhancing the readability and maintainability of your code:

from pack_your_code import got_code

These prove to be a favorite method among Python developers due to their transparency.

Making code test-ready with the Main section

Include a test section in your script by making use of a common Python convention:

if __name__ == '__main__': # Now for some fun! Test away, folks!

This practice allows for neat, independent testing of individual modules.

Running scripts: A guided tour

The practice of running scripts from within the package directory tends to complicate import statements. Hence, when you run a module and expect it to work with relative imports, it's typically preferred to use:

python -m pack_your_code.got_code

ImportErrors: Here's looking at you, kid!

Facing an ImportError? Look for standard stumbling blocks:

  • __init__.py not in place.
  • Package structure: It's slightly off.
  • Running a script from within a package directory, instead of the parent directory.
  • Your module isn't included in sys.path.

Keep these in mind to avoid and rectify import errors.

Smarter import strategy for your projects

When setting up your project, leverage a structured approach that can support scalable import methods while being in sync with emerging tools and best practices.

Managing and installing packages: Suit up!

For managing your Python packages, packaging tools such as pip, setuptools, poetry, or flit come in handy. These automate package installation and simplify dependency management, making your code more transportable and reducing import error incidence.

Dev-friendly editable installs

During development, pip install -e . lets you engage with editable installs - changes to the package's source code reflect immediately without reinstallations. It's like having your cake and eating it too!

Console script entry points: Make an entrance!

Defining console script entry points in your setup.py (or equivalent packaging configuration) lets you execute your module as a command-line tool. Directory structures won’t stop you!