| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- # -*- 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)
|