This template provides a foundational structure for a Python class that uses lazy-loading to avoid circular imports and unnecessary initialization. The class also includes functionality for logging, dynamic dependency injection, and data validation using Pydantic.
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, List, Dict, Any
from pydantic import BaseModel, ValidationError
import logging
# Conditional imports to avoid circular dependencies
if TYPE_CHECKING:
from your_module_name_here import DependentClass1, DependentClass2 # Replace with actual class/module names
# Pydantic BaseModel example for data validation
class ExampleModel(BaseModel):
id: str
value: int
description: Optional[str] = None
class LazyLoadedClass:
"""
A template class with lazy-loaded dependencies to avoid circular imports and unnecessary initialization.
Attributes:
param1 (str): A parameter to demonstrate class initialization.
param2 (int): Another parameter to demonstrate class initialization.
_dependent_class1 (Optional[DependentClass1]): Lazy-loaded instance of DependentClass1.
_dependent_class2 (Optional[DependentClass2]): Lazy-loaded instance of DependentClass2.
_logger (Optional[logging.Logger]): Lazy-loaded logger instance.
"""
def __init__(self, param1: str, param2: int):
self.param1 = param1
self.param2 = param2
self._dependent_class1: Optional[DependentClass1] = None
self._dependent_class2: Optional[DependentClass2] = None
self._logger: Optional[logging.Logger] = None
@property
def logger(self) -> logging.Logger:
"""Lazy-load the logger."""
if self._logger is None:
self._logger = logging.getLogger(self.__class__.__name__)
self._logger.setLevel(logging.INFO) # Default to INFO level, adjust as needed
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
self._logger.addHandler(handler)
self._logger.debug("Logger initialized for %s", self.__class__.__name__)
return self._logger
@property
def dependent_class1(self) -> DependentClass1:
"""Lazy-load DependentClass1."""
if self._dependent_class1 is None:
from your_module_name_here import DependentClass1 # Replace with actual module
self._dependent_class1 = DependentClass1()
self.logger.debug("DependentClass1 initialized")
return self._dependent_class1
@property
def dependent_class2(self) -> DependentClass2:
"""Lazy-load DependentClass2."""
if self._dependent_class2 is None:
from your_module_name_here import DependentClass2 # Replace with actual module
self._dependent_class2 = DependentClass2()
self.logger.debug("DependentClass2 initialized")
return self._dependent_class2
def some_method(self) -> None:
"""A method demonstrating the usage of lazy-loaded dependencies."""
try:
result1 = self.dependent_class1.some_method()
result2 = self.dependent_class2.another_method()
self.logger.info("Successfully called methods on lazy-loaded classes")
except Exception as e:
self.logger.error("Error in some_method: %s", str(e))
raise
def to_dict(self) -> Dict[str, Any]:
"""Convert the class attributes to a dictionary."""
try:
return {
"param1": self.param1,
"param2": self.param2,
"dependent_class1": self.dependent_class1.to_dict(),
"dependent_class2": self.dependent_class2.to_dict(),
}
except Exception as e:
self.logger.error("Error converting to dict: %s", str(e))
raise
def add_dependent_class(self, class_type: str, class_instance: Any) -> None:
"""
Dynamically add a dependent class instance to the LazyLoadedClass.
Args:
class_type (str): The name of the class being added (e.g., 'dependent_class1').
class_instance (Any): The instance of the class being added.
Raises:
ValueError: If the class_type is not recognized.
"""
if class_type == 'dependent_class1':
self._dependent_class1 = class_instance
elif class_type == 'dependent_class2':
self._dependent_class2 = class_instance
else:
self.logger.error("Invalid class_type provided: %s", class_type)
raise ValueError(f"Invalid class_type: {class_type}")
def validate_model(self, data: Dict[str, Any]) -> ExampleModel:
"""
Validate input data against the ExampleModel schema.
Args:
data (Dict[str, Any]): The data to be validated.
Returns:
ExampleModel: The validated model instance.
Raises:
ValidationError: If the data is not valid according to ExampleModel.
"""
try:
model = ExampleModel(**data)
self.logger.info("Data successfully validated against ExampleModel")
return model
except ValidationError as e:
self.logger.error("Validation error: %s", str(e))
raise
# Usage example demonstrating lazy loading and data validation
if __name__ == "__main__":
try:
example = LazyLoadedClass(param1="example", param2=123)
example.some_method()
validated_model = example.validate_model({"id": "1", "value": 10})
print(validated_model.dict())
example_dict = example.to_dict()
print(example_dict)
except Exception as e:
logging.error("Error in usage example: %s", str(e))