Organizing code into modules and packages is a cornerstone of Python development. However, knowing how to import that code can be confusing. This guide breaks down the two main import styles, absolute and relative, and explains why absolute imports are almost always the better choice.
How Python Finds Modules
When you write import math, Python searches for the module in this order:
- Sys Modules Cache: Checks if the module is already loaded.
- Built-in Modules: Checks standard libraries like
os,sys, andjson. - Sys Path: Searches directories in
sys.path, which includes your current directory and installedsite-packages.
Using Absolute Imports
An absolute import specifies the full path from the project's root directory to the module. It does not matter where the current file is located; only the project structure matters.
Example Project Structure
my_project/
├── main.py
└── ecommerce/
├── __init__.py
├── database.py
└── payments/
├── __init__.py
└── stripe.pyTo import the database module inside stripe.py, use the full path:
from ecommerce import database
def process_payment():
database.save_transaction()You can also import specific functions or classes:
from ecommerce.database import save_transaction, get_user
def process_payment():
user = get_user()
save_transaction()Benefits of Absolute Imports
- Clarity: The full path shows exactly where the module lives.
- Robustness: Moving files to different folders does not break import statements.
- Consistency: Works the same way whether running as a script or importing as a module.
Using Relative Imports
A relative import uses dot notation to define where the module is relative to the current file:
.refers to the current directory..refers to the parent directory...refers to the grandparent directory
Example Usage
Inside stripe.py (located in ecommerce/payments/), you can import database.py (located in ecommerce/) like this:
from .. import database
def process_payment():
database.save_transaction()To import from a sibling module in the same directory:
from . import utils
from .helpers import format_currencyRunning Modules Correctly
To run a module that uses relative imports, use the -m flag:
python -m ecommerce.payments.stripeThis tells Python to treat the file as part of the package structure.
Best Practices
Following PEP 8 guidelines ensures consistent and maintainable code.
Import Ordering
Group imports in this order, with a blank line between each group:
import os
import sys
from datetime import datetime
import requests
from sqlalchemy import create_engine
from ecommerce import database
from ecommerce.payments import stripeWhen to Use Each Style
Common Import Patterns
Importing Multiple Items
from ecommerce.database import (
save_transaction,
get_user,
update_inventory,
)
from ..database import (
save_transaction,
get_user,
update_inventory,
)Aliasing Imports
from ecommerce.payments.stripe import StripePaymentProcessor as PaymentProcessor
import numpy as npConditional Imports
try:
import ujson as json
except ImportError:
import jsonComparison Summary
| Feature | Absolute Import | Relative Import |
|---|---|---|
| Syntax | from package.module import func |
from .module import func |
| Readability | High (clear path) | Medium (context dependent) |
| Refactoring | Resilient to file moves | Breaks when files move |
| Script Execution | Works everywhere | Fails in __main__ context |
| PEP 8 Recommendation | Preferred | Acceptable for complex packages |
Summary
Absolute imports provide clarity, consistency, and resilience to code refactoring, making them the recommended choice for most Python projects. Relative imports serve a purpose in complex packages with stable internal structures but should be used sparingly. Following PEP 8 guidelines for import ordering and grouping keeps your codebase maintainable and readable.