Skip to Content
Course content

160: Relative vs Absolute Imports

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Imagine you're giving someone directions to a specific office in a massive corporate skyscraper. You have two ways to do it. You could give them the absolute address: "Go to the 12th floor, Suite 1205." It doesn't matter if they're currently in the lobby or the basement; those directions always lead to the same door. Or, you could give them relative directions: "Go up two floors and take the first door on the right." Now, those directions only work if the person is already standing on the 10th floor. If they're in the lobby, they'll end up in the wrong place entirely.

In Python, imports work exactly like this. An absolute import is the "Suite 1205" approach—it starts from the project root. A relative import is the "two floors up" approach—it depends entirely on where the current file sits in the folder hierarchy.

The "Full Address" Approach

Absolute imports are the gold standard. They specify the complete path from the project's root directory. Let's say we're building a simple e-commerce system with this structure:

ecommerce/
├── main.py
└── store/
    ├── __init__.py
    ├── orders.py
    └── payments/
        ├── __init__.py
        └── stripe_gateway.py

If I'm writing code inside stripe_gateway.py and I need a class from orders.py, an absolute import looks like this:

from store.orders import Order

I love absolute imports because they are explicit. If I move stripe_gateway.py to a different folder later, I only have to update the import if the store.orders path itself changes. It's clear, it's readable, and it's what PEP 8 (the Python style guide) generally recommends.

Navigating by Landmarks

Relative imports use leading dots to indicate how many levels "up" to go. A single dot . means "current package," and two dots .. mean "parent package."

Back in our stripe_gateway.py file, since it's inside the payments folder, and orders.py is one level up in the store folder, I can do this:

from ..orders import Order

This is handy when you're building a massive library with dozens of sub-packages. If you decide to rename the top-level store folder to shop, you don't have to go through fifty files and change from store... to from shop.... The relative import just keeps working because the "landmark" (one level up) hasn't changed.

Where things usually break

Here is the part where most developers pull their hair out: relative imports do not work if you run the script containing them directly.

If you open your terminal and run python store/payments/stripe_gateway.py, Python treats that file as the "top-level script." In its mind, there is no "parent package" because you told it that stripe_gateway.py is the starting point. You'll get a ImportError: attempted relative import with no known parent package.

I've seen this trip up even senior devs. The rule of thumb is: use relative imports for internal package organization, but always execute your code from a main entry point (like main.py) at the root of your project. That way, Python understands the full package hierarchy and knows exactly where those "dots" are leading.




📋 Practical Task

Fixing the Broken Invoice Generator Import

You've inherited a project for a billing system, but the developer who wrote it left it in a broken state. The project structure is as follows:

billing_system/
├── run.py
└── core/
    ├── __init__.py
    ├── calculator.py
    └── reports/
        ├── __init__.py
        └── invoice_gen.py

Inside invoice_gen.py, there is a line attempting to import a function called calculate_tax from calculator.py, but it's currently written as:

from calculator import calculate_tax

This is failing because calculator.py is not in the same folder as invoice_gen.py.

Your Task:

  • Rewrite the import statement in invoice_gen.py using a relative import to correctly reference calculator.py.
  • Rewrite the same import statement using an absolute import (starting from the core package).
  • Briefly explain why running python core/reports/invoice_gen.py directly would still cause an error even after you fix the import.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.