
Python
Learn advanced import patterns for complex projects and performance optimization.
Handle circular imports elegantly in complex codebases.
# ❌ Problematic circular imports
# models.py
from . import views
class User:
def render(self):
return views.render_user(self)
# views.py
from . import models
def render_user(user):
return models.User # Circular!
# ✅ Solution 1: Late imports
# models.py
class User:
def render(self):
from . import views # Import inside method
return views.render_user(self)
# views.py
from . import models
def render_user(user):
return user
# ✅ Solution 2: Restructure into multiple modules
# interfaces.py
class UserBase:
pass
# models.py
from .interfaces import UserBase
class User(UserBase):
pass
# views.py
def render_user(user):
return str(user)Detecting circular imports:
import sys
def detect_circular_imports():
"""Find potential circular dependencies."""
modules = sys.modules.copy()
for name, module in modules.items():
if module is None or not hasattr(module, "__dict__"):
continue
# Check module's __dict__ for imports
for attr_name, attr_value in module.__dict__.items():
if isinstance(attr_value, type(sys)):
# This module imports another
passImport different implementations based on conditions.
# database.py - Conditional database imports
import sys
# Import based on installed packages
try:
import psycopg2
DATABASE_BACKEND = "postgresql"
except ImportError:
try:
import mysql.connector
DATABASE_BACKEND = "mysql"
except ImportError:
import sqlite3
DATABASE_BACKEND = "sqlite"
class Database:
@classmethod
def connect(cls, connection_string):
if DATABASE_BACKEND == "postgresql":
return psycopg2.connect(connection_string)
elif DATABASE_BACKEND == "mysql":
return mysql.connector.connect(connection_string)
else:
return sqlite3.connect(connection_string)Version-specific imports:
import sys
# Import based on Python version
if sys.version_info >= (3, 10):
from typing import ParamSpec # Python 3.10+
else:
from typing_extensions import ParamSpec # Backport
# Use modern features when available
if sys.version_info >= (3, 9):
from typing import Annotated # Built-in in 3.9+
else:
from typing_extensions import AnnotatedSafely modify modules at runtime.
# Original module: mymodule.py
def original_function():
return "original"
# runtime_patches.py
import mymodule
# Store original
_original_function = mymodule.original_function
def patched_function():
"""Enhanced version of original function."""
result = _original_function()
return f"patched: {result}"
# Apply patch
mymodule.original_function = patched_function
# Now all code using mymodule gets patched version
result = mymodule.original_function() # "patched: original"Context manager for temporary patches:
from contextlib import contextmanager
@contextmanager
def patch_module(module, attr_name, value):
"""Temporarily patch module attribute."""
old_value = getattr(module, attr_name)
setattr(module, attr_name, value)
try:
yield
finally:
setattr(module, attr_name, old_value)
# Usage
import time
with patch_module(time, "sleep", lambda x: None):
# time.sleep() does nothing in this block
time.sleep(10) # Instant!
# time.sleep() restored after block
time.sleep(0.1) # Actually sleepsLoad modules dynamically based on configuration or discovery.
import importlib
import os
from pathlib import Path
class PluginLoader:
"""Load plugins from directory."""
def __init__(self, plugin_dir):
self.plugin_dir = Path(plugin_dir)
self.plugins = {}
def load_all(self):
"""Discover and load all plugins."""
for py_file in self.plugin_dir.glob("*.py"):
if not py_file.name.startswith("_"):
self.load_plugin(py_file.stem)
def load_plugin(self, name):
"""Load single plugin."""
spec = importlib.util.spec_from_file_location(
name,
self.plugin_dir / f"{name}.py"
)
module = importlib.util.module_from_spec(spec)
sys.modules[name] = module
spec.loader.exec_module(module)
self.plugins[name] = module
return module
def reload_plugin(self, name):
"""Reload plugin (useful in development)."""
if name in sys.modules:
del sys.modules[name]
return self.load_plugin(name)Configuration-driven imports:
import importlib
import json
# config.json
config = {
"handlers": {
"json": "handlers.json_handler",
"csv": "handlers.csv_handler",
"xml": "handlers.xml_handler"
}
}
class HandlerFactory:
"""Load handlers from configuration."""
@staticmethod
def get_handler(format_type):
"""Load handler class based on format."""
if format_type not in config["handlers"]:
raise ValueError(f"Unknown format: {format_type}")
module_path = config["handlers"][format_type]
module_name, class_name = module_path.rsplit(".", 1)
module = importlib.import_module(module_name)
handler_class = getattr(module, class_name)
return handler_class()
# Usage
handler = HandlerFactory.get_handler("json")import sys
import time
import importlib
class ImportOptimizer:
"""Analyze and optimize imports."""
@staticmethod
def measure_import_time(module_name):
"""Measure import time."""
start = time.time()
importlib.import_module(module_name)
return time.time() - start
@staticmethod
def find_slow_imports(modules, threshold=0.1):
"""Find imports taking too long."""
slow = []
for module in modules:
elapsed = ImportOptimizer.measure_import_time(module)
if elapsed > threshold:
slow.append((module, elapsed))
return sorted(slow, key=lambda x: x[1], reverse=True)
@staticmethod
def optimize_startup():
"""Lazy import strategy."""
# Fast built-in imports
import sys
import os
# Defer heavy imports
def get_numpy():
return __import__("numpy")
def get_pandas():
return __import__("pandas")
return {
"numpy": get_numpy,
"pandas": get_pandas
}
# Usage
optimizer = ImportOptimizer()
slow = optimizer.find_slow_imports(["numpy", "pandas", "requests"])# Package __init__.py with advanced features
__version__ = "1.0.0"
__all__ = ["api", "models", "utils"]
# Lazy loading entire subpackages
def __getattr__(name):
"""Lazy import submodules."""
if name == "api":
from . import api
return api
elif name == "models":
from . import models
return models
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
def __dir__():
"""Support dir() on package."""
return sorted(__all__)
# Conditional imports for optional features
try:
from .database import Database
HAS_DATABASE = True
except ImportError:
HAS_DATABASE = False
# Configuration at package level
_config = {
"debug": False,
"version": __version__
}
def get_config():
"""Get package configuration."""
return _config.copy()# Handle complex dependency chains
import importlib
from typing import Dict, List, Set
class DependencyResolver:
"""Resolve import dependencies."""
def __init__(self):
self.dependencies: Dict[str, Set[str]] = {}
def add_dependency(self, module: str, depends_on: str):
"""Register module dependency."""
if module not in self.dependencies:
self.dependencies[module] = set()
self.dependencies[module].add(depends_on)
def load_in_order(self, target_module: str):
"""Load module with all dependencies."""
to_load = self._topological_sort(target_module)
loaded = {}
for module in to_load:
loaded[module] = importlib.import_module(module)
return loaded
def _topological_sort(self, module: str) -> List[str]:
"""Sort modules by dependency order."""
visited = set()
order = []
def visit(m):
if m in visited:
return
visited.add(m)
if m in self.dependencies:
for dep in self.dependencies[m]:
visit(dep)
order.append(m)
visit(module)
return orderReady to practice? Challenges | Quiz
Resources
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