# -*- coding: utf-8 -*- """ Lazy-Service-Wrapper für verzögerte Initialisierung. Ermöglicht die Deklaration von Service-Abhängigkeiten ohne sofortige Instanziierung. """ from __future__ import annotations import threading from typing import Callable, Generic, TypeVar, Any T = TypeVar("T") class LazyService(Generic[T]): """ Wrapper für verzögerte Service-Initialisierung. Die Instanz wird erst beim ersten Zugriff erstellt. Alle Attributzugriffe werden an die Instanz delegiert. Example: # Factory für verzögerte Erstellung db_service = LazyService(lambda: DatabaseService()) # Keine Instanz erstellt print(db_service.is_initialized) # False # Erster Zugriff erstellt die Instanz result = db_service.query("SELECT * FROM users") print(db_service.is_initialized) # True """ __slots__ = ( "_factory", "_instance", "_initialized", "_lock", "_initializing", ) def __init__(self, factory: Callable[[], T]) -> None: """ Initialisiert den LazyService. Args: factory: Factory-Funktion zur Instanz-Erstellung. """ object.__setattr__(self, "_factory", factory) object.__setattr__(self, "_instance", None) object.__setattr__(self, "_initialized", False) object.__setattr__(self, "_lock", threading.Lock()) object.__setattr__(self, "_initializing", False) def _get_instance(self) -> T: """ Holt oder erstellt die Instanz. Thread-safe durch Double-Checked Locking. Returns: Die Service-Instanz. """ if self._initialized: return self._instance # type: ignore with self._lock: if not self._initialized: if self._initializing: raise RuntimeError( "Zirkuläre Abhängigkeit bei Lazy-Initialisierung" ) object.__setattr__(self, "_initializing", True) try: instance = self._factory() object.__setattr__(self, "_instance", instance) object.__setattr__(self, "_initialized", True) finally: object.__setattr__(self, "_initializing", False) return self._instance # type: ignore @property def is_initialized(self) -> bool: """Prüft, ob die Instanz bereits erstellt wurde.""" return self._initialized @property def instance(self) -> T: """Gibt die Instanz zurück (erstellt sie bei Bedarf).""" return self._get_instance() def reset(self) -> None: """ Setzt den LazyService zurück. Die nächste Zugriff erstellt eine neue Instanz. """ with self._lock: if self._initialized and self._instance is not None: # Dispose aufrufen falls vorhanden if hasattr(self._instance, "dispose"): try: self._instance.dispose() except Exception: pass elif hasattr(self._instance, "close"): try: self._instance.close() except Exception: pass object.__setattr__(self, "_instance", None) object.__setattr__(self, "_initialized", False) def __getattr__(self, name: str) -> Any: """Delegiert Attributzugriffe an die Instanz.""" # Vermeidet Endlosrekursion bei speziellen Attributen if name.startswith("_"): raise AttributeError( f"'{type(self).__name__}' object has no attribute '{name}'" ) return getattr(self._get_instance(), name) def __setattr__(self, name: str, value: Any) -> None: """Delegiert Attributsetzungen an die Instanz.""" if name.startswith("_"): object.__setattr__(self, name, value) else: setattr(self._get_instance(), name, value) def __delattr__(self, name: str) -> None: """Delegiert Attributlöschungen an die Instanz.""" if name.startswith("_"): object.__delattr__(self, name) else: delattr(self._get_instance(), name) def __call__(self, *args: Any, **kwargs: Any) -> Any: """Ermöglicht Aufruf als Funktion.""" instance = self._get_instance() if callable(instance): return instance(*args, **kwargs) raise TypeError( f"'{type(instance).__name__}' object is not callable" ) def __repr__(self) -> str: """String-Repräsentation.""" if self._initialized: return f"LazyService(initialized={self._instance!r})" return f"LazyService(pending)" def __bool__(self) -> bool: """Boolean-Konvertierung.""" return bool(self._get_instance()) class LazyProxy(Generic[T]): """ Proxy für lazy-geladene Services mit vollständiger Delegation. Ähnlich wie LazyService, aber mit erweiterter Protokoll- Unterstützung (Iterator, Context Manager, etc.). """ def __init__(self, factory: Callable[[], T]) -> None: """ Initialisiert den LazyProxy. Args: factory: Factory-Funktion zur Instanz-Erstellung. """ object.__setattr__(self, "_lazy_factory", factory) object.__setattr__(self, "_lazy_instance", None) object.__setattr__(self, "_lazy_initialized", False) object.__setattr__(self, "_lazy_lock", threading.Lock()) def _lazy_get_instance(self) -> T: """Holt oder erstellt die Instanz.""" if not self._lazy_initialized: with self._lazy_lock: if not self._lazy_initialized: instance = self._lazy_factory() object.__setattr__(self, "_lazy_instance", instance) object.__setattr__(self, "_lazy_initialized", True) return self._lazy_instance # type: ignore def __getattr__(self, name: str) -> Any: """Delegiert Attributzugriffe.""" if name.startswith("_lazy_"): raise AttributeError(name) return getattr(self._lazy_get_instance(), name) def __setattr__(self, name: str, value: Any) -> None: """Delegiert Attributsetzungen.""" if name.startswith("_lazy_"): object.__setattr__(self, name, value) else: setattr(self._lazy_get_instance(), name, value) def __iter__(self): """Iterator-Protokoll.""" return iter(self._lazy_get_instance()) def __len__(self) -> int: """Length-Protokoll.""" return len(self._lazy_get_instance()) # type: ignore def __getitem__(self, key: Any) -> Any: """Item-Protokoll.""" return self._lazy_get_instance()[key] # type: ignore def __setitem__(self, key: Any, value: Any) -> None: """Item-Setzung.""" self._lazy_get_instance()[key] = value # type: ignore def __enter__(self) -> T: """Context-Manager-Eintritt.""" return self._lazy_get_instance().__enter__() # type: ignore def __exit__(self, exc_type, exc_val, exc_tb) -> Any: """Context-Manager-Austritt.""" return self._lazy_get_instance().__exit__(exc_type, exc_val, exc_tb) # type: ignore def __await__(self): """Await-Protokoll für async.""" return self._lazy_get_instance().__await__() # type: ignore def lazy(factory: Callable[[], T]) -> LazyService[T]: """ Factory-Funktion für LazyService. Args: factory: Factory-Funktion. Returns: LazyService-Instanz. Example: @lazy def create_service(): return ExpensiveService() service = create_service # Oder: service = lazy(lambda: ExpensiveService()) """ return LazyService(factory)