Skip to content

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:

  1. __init__.py in each directory (makes it a package)
  2. 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 + -m flag)
  • Use python -m package.module to 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