Relative Imports¶
Relative imports allow modules within a package to import each other using dot notation, without specifying the full package path.
Syntax¶
| Syntax | Meaning |
|---|---|
. |
Current package (same directory) |
.. |
Parent package (one level up) |
... |
Grandparent package (two levels up) |
from . import sibling # Same directory
from .sibling import func # Function from sibling
from .. import parent_module # Parent directory
from ..utils import helper # Module in parent's utils/
Example Package Structure¶
mypackage/
├── __init__.py
├── core.py
├── utils.py
└── sub/
├── __init__.py
├── module_a.py
└── module_b.py
In sub/module_a.py¶
# Import from same directory
from . import module_b
from .module_b import some_function
# Import from parent package
from .. import core
from .. import utils
from ..utils import helper_function
# Import from parent's sibling (if existed)
# from ..other_sub import something
In core.py¶
# Import from same directory
from . import utils
from .utils import helper
# Import subpackage
from .sub import module_a
from .sub.module_a import func
Relative vs Absolute Imports¶
Absolute Import¶
from mypackage.sub.module_a import func
from mypackage.utils import helper
- Full path from top-level package
- Works from anywhere
- More explicit
Relative Import¶
from .module_a import func
from ..utils import helper
- Path relative to current module
- Shorter for internal imports
- Requires package context
When Relative Imports Work¶
Relative imports require:
__init__.pyin each directory (makes it a package)- Module execution as part of a package (not directly as script)
This Works¶
project/
├── mypackage/
│ ├── __init__.py
│ ├── main.py
│ └── utils.py
# mypackage/main.py
from .utils import helper # ✅ Works when imported as package
# Run as module (from project directory)
python -m mypackage.main # ✅ Works
This Fails¶
# Run as script
python mypackage/main.py # ❌ ImportError
Error:
ImportError: attempted relative import with no known parent package
Why Direct Script Execution Fails¶
When you run python mypackage/main.py:
- Python sets
__name__ = "__main__" - Python sets
__package__ = None - No package context exists
- Relative imports cannot resolve
When you run python -m mypackage.main:
- Python sets
__name__ = "__main__" - Python sets
__package__ = "mypackage" - Package context exists
- Relative imports work
The -m Flag¶
Always use -m to run modules inside packages:
# From project root (parent of mypackage)
python -m mypackage.main # ✅ Correct
python -m mypackage.sub.module_a # ✅ Correct
# Don't do this
python mypackage/main.py # ❌ Breaks relative imports
Without __init__.py¶
Since Python 3.3 (PEP 420), packages can exist without __init__.py (namespace packages).
But relative imports still require __init__.py:
mypackage/
├── core.py # No __init__.py
└── utils.py
# core.py
from .utils import helper # ❌ ImportError
Add __init__.py to enable relative imports:
mypackage/
├── __init__.py # Can be empty
├── core.py
└── utils.py
# core.py
from .utils import helper # ✅ Works
Common Patterns¶
Import Sibling Module¶
# In mypackage/module_a.py
from . import module_b
from .module_b import some_class
Import from Parent¶
# In mypackage/sub/child.py
from .. import parent_module
from ..parent_module import ParentClass
Import Within init.py¶
# mypackage/__init__.py
from .core import MainClass
from .utils import helper
__all__ = ['MainClass', 'helper']
Absolute vs Relative: When to Use¶
| Use Case | Recommendation |
|---|---|
| Internal package imports | Relative (shorter, refactor-friendly) |
| External package imports | Absolute (always) |
Public API in __init__.py |
Either works |
| Cross-package imports | Absolute |
Example Mixed Usage¶
# mypackage/core.py
# External: always absolute
import numpy as np
from pandas import DataFrame
# Internal: relative is cleaner
from .utils import helper
from .sub import processor
Debugging Relative Import Issues¶
Check Package Context¶
# Add to your module
print(f"__name__: {__name__}")
print(f"__package__: {__package__}")
When run correctly:
__name__: mypackage.main
__package__: mypackage
When run as script (broken):
__name__: __main__
__package__: None
Verify __init__.py Exists¶
ls mypackage/__init__.py
ls mypackage/sub/__init__.py
Every directory in the import chain needs __init__.py for relative imports.
Summary¶
| Scenario | Works? | Solution |
|---|---|---|
python -m pkg.module |
✅ | — |
python pkg/module.py |
❌ | Use -m flag |
Missing __init__.py |
❌ | Add __init__.py |
| Top-level script with relative | ❌ | Use absolute imports |
Key Takeaways¶
.= current package,..= parent package- Relative imports require package context (
__init__.py+-mflag) - Use
python -m package.moduleto run modules inside packages - Each directory in the chain needs
__init__.py - Use relative imports for internal package code
- Use absolute imports for external packages