Ojasa Mirai

Ojasa Mirai

Python

Loading...

Learning Level

🟢 BeginneršŸ”µ Advanced
Modules Import BasicsCreating ModulesImport StatementsRelative ImportsImport PathsPackages StructureNamespace PackagesPip & DependenciesModule Performance
Python/Modules Packages/Relative Imports

šŸŽÆ Advanced Relative Import Patterns

Solve complex import scenarios in deeply nested packages and multi-level hierarchies.


šŸŽÆ Deep Package Hierarchies

Navigate complex multi-level package structures.

company/
ā”œā”€ā”€ __init__.py
ā”œā”€ā”€ core/
│   ā”œā”€ā”€ __init__.py
│   └── models.py
ā”œā”€ā”€ services/
│   ā”œā”€ā”€ __init__.py
│   ā”œā”€ā”€ user/
│   │   ā”œā”€ā”€ __init__.py
│   │   ā”œā”€ā”€ models.py
│   │   └── handlers.py
│   └── order/
│       ā”œā”€ā”€ __init__.py
│       ā”œā”€ā”€ models.py
│       └── handlers.py
└── utils/
    ā”œā”€ā”€ __init__.py
    └── validators.py

In company/services/user/handlers.py:

# Import from sibling module (same level)
from .models import User

# Import from parent package's sibling
from ..order.models import Order

# Import from grandparent package's child
from ...core.models import BaseModel

# Import from utils (multiple levels up)
from ...utils.validators import validate_email

class UserHandler:
    def handle_user_order(self, user: User, order: Order):
        """Handler combining models from different packages."""
        if not validate_email(user.email):
            raise ValueError("Invalid email")
        return {"user": user, "order": order}

šŸ’” Circular Import Prevention in Deep Hierarchies

Solve circular imports across multiple levels.

# Problem: circular import across levels
# company/services/user/models.py
from ...core.models import BaseModel
from .handlers import UserHandler  # Circular if handlers imports this

# company/services/user/handlers.py
from .models import User  # Circular!

Solution 1: Structural reorganization:

# Separate models and handlers
company/
ā”œā”€ā”€ models/
│   ā”œā”€ā”€ __init__.py
│   ā”œā”€ā”€ user.py
│   └── order.py
└── handlers/
    ā”œā”€ā”€ __init__.py
    ā”œā”€ā”€ user.py
    └── order.py
# company/models/user.py
from ...core.models import BaseModel

class User(BaseModel):
    pass

# company/handlers/user.py (no circular dependency)
from ..models.user import User

class UserHandler:
    pass

Solution 2: TYPE_CHECKING imports:

from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from .handlers import UserHandler

class User:
    def render(self) -> "UserHandler":
        # Only imports at type-check time, not runtime
        from .handlers import UserHandler
        return UserHandler().render(self)

šŸ—ļø Package __init__.py Architecture

Design __init__.py for complex hierarchies.

# company/__init__.py - Root package initialization

from . import core
from . import services
from . import utils

__version__ = "1.0.0"
__all__ = ["core", "services", "utils"]

# company/services/__init__.py - Services subpackage
from . import user
from . import order

__all__ = ["user", "order"]

# company/services/user/__init__.py - User service package
from .models import User, UserProfile
from .handlers import UserHandler

__all__ = ["User", "UserProfile", "UserHandler"]

# Now users can do:
from company.services.user import User
from company.services import order

šŸ“¦ Relative Import Type Compatibility

Handle different relative import scenarios.

# company/services/user/models.py

# āœ… Valid: Same package, same level
from . import handlers

# āœ… Valid: Sibling subpackage
from ..order import models as order_models

# āœ… Valid: Parent package
from .. import validators

# āœ… Valid: Grandparent
from ... import core

# āœ… Valid: Grandparent's child
from ...core.models import BaseModel

# āŒ Invalid: Can't go above top level
from .... import something  # Would try to go above company

# āŒ Invalid: Can't use relative with absolute in same statement
from ..order import Order
import external_package  # Fine separately, but mixing is confusing

šŸ”„ Multi-Package Systems

Organize multiple interdependent packages.

project/
ā”œā”€ā”€ package_a/
│   ā”œā”€ā”€ __init__.py
│   ā”œā”€ā”€ module_a.py
│   └── subpkg/
│       ā”œā”€ā”€ __init__.py
│       └── module_a_sub.py
└── package_b/
    ā”œā”€ā”€ __init__.py
    ā”œā”€ā”€ module_b.py
    └── subpkg/
        ā”œā”€ā”€ __init__.py
        └── module_b_sub.py

In package_b/module_b.py:

# Can import from package_a (different top-level package)
# But only with absolute imports (no relative imports across packages)
import package_a
from package_a.module_a import ClassA

# Within package_b, use relative imports
from . import subpkg
from .subpkg.module_b_sub import ClassBSub

šŸ’» Export Aggregation Pattern

Use relative imports to aggregate and expose package APIs.

# company/services/__init__.py - Aggregate service APIs

# Import all public items from subpackages
from .user import User, UserHandler
from .user import UserService
from .order import Order, OrderHandler
from .order import OrderService

# Re-export as package API
__all__ = [
    "User",
    "UserHandler",
    "UserService",
    "Order",
    "OrderHandler",
    "OrderService"
]

# Users can now do:
from company.services import User, Order
# Instead of:
# from company.services.user import User
# from company.services.order import Order

Lazy re-export:

# company/services/__init__.py - Lazy export

def __getattr__(name):
    """Lazy import for performance."""
    if name == "User":
        from .user import User
        return User
    elif name == "Order":
        from .order import Order
        return Order
    raise AttributeError(f"module {__name__} has no attribute {name}")

def __dir__():
    return ["User", "Order"]

šŸŽØ Template Pattern for Package Layout

Best practices template:

myproject/
ā”œā”€ā”€ setup.py
ā”œā”€ā”€ setup.cfg
└── src/
    └── myproject/           # Top-level package
        ā”œā”€ā”€ __init__.py      # Version, exports
        ā”œā”€ā”€ core/            # Core functionality
        │   ā”œā”€ā”€ __init__.py
        │   ā”œā”€ā”€ models.py
        │   └── utils.py
        ā”œā”€ā”€ services/        # Business logic
        │   ā”œā”€ā”€ __init__.py
        │   ā”œā”€ā”€ user/
        │   │   ā”œā”€ā”€ __init__.py
        │   │   ā”œā”€ā”€ models.py
        │   │   └── handlers.py
        │   └── order/
        │       ā”œā”€ā”€ __init__.py
        │       ā”œā”€ā”€ models.py
        │       └── handlers.py
        └── api/             # API layer
            ā”œā”€ā”€ __init__.py
            ā”œā”€ā”€ v1/
            │   ā”œā”€ā”€ __init__.py
            │   ā”œā”€ā”€ users.py
            │   └── orders.py
            └── v2/
                ā”œā”€ā”€ __init__.py
                ā”œā”€ā”€ users.py
                └── orders.py

myproject/__init__.py:

__version__ = "1.0.0"

from . import core
from . import services
from . import api

__all__ = ["core", "services", "api"]

myproject/services/__init__.py:

# Use relative imports
from . import user
from . import order

__all__ = ["user", "order"]

myproject/services/user/__init__.py:

from .models import User
from .handlers import UserHandler

__all__ = ["User", "UserHandler"]

šŸ”‘ Import Strategy Guide

When to use relative imports:

# āœ… Within same package/subpackage
from .models import User

# āœ… Accessing parent package siblings
from ..order import Order

# āœ… Accessing utilities from parent
from ...utils import validators

When to use absolute imports:

# āœ… Different top-level packages
from package_a import something

# āœ… External libraries
import numpy as np

# āœ… From installed packages
from requests import get

šŸ”‘ Key Takeaways

  • āœ… Use relative imports only within packages
  • āœ… One dot (.) = current package
  • āœ… Two dots (..) = parent package
  • āœ… Solve circular imports with late imports or restructuring
  • āœ… Use TYPE_CHECKING for type hints without circular imports
  • āœ… Aggregate exports in __init__.py for clean APIs
  • āœ… Use __getattr__ for lazy package loading

Ready to practice? Challenges | Quiz


Resources

Python Docs

Ojasa Mirai

Master AI-powered development skills through structured learning, real projects, and verified credentials. Whether you're upskilling your team or launching your career, we deliver the skills companies actually need.

Learn Deep • Build Real • Verify Skills • Launch Forward

Courses

PythonFastapiReactJSCloud

Ā© 2026 Ojasa Mirai. All rights reserved.

TwitterGitHubLinkedIn