Source code for bqskit.utils.cachedclass

"""This module implements the CachedClass base classes."""
from __future__ import annotations

import logging
from typing import Any
from typing import Hashable
from typing import TypeVar

from bqskit.utils.docs import building_docs

if not building_docs():
    from numpy.lib.mixins import NDArrayOperatorsMixin
else:
    class NDArrayOperatorsMixin:  # type: ignore
        pass


_logger = logging.getLogger(__name__)


T = TypeVar('T')


[docs] class CachedClass: """ A class that caches its instances. Any class that inherits from CachedClass will be instantiated once per parameter set. Any subsequent attempts to instantiate a CachedClass with the same parameters will return the same object. CachedClass is not thread-safe. Examples: >>> x = CachedClass(1) >>> y = CachedClass(1) >>> z = CachedClass(2) >>> x is y True >>> x is z False """ _instances: dict[Any, CachedClass] = {} def __new__(cls: type[T], *args: Any, **kwargs: Any) -> T: hash_a = all( isinstance(arg, Hashable) and not isinstance(arg, NDArrayOperatorsMixin) for arg in args ) hash_kw = all( isinstance(arg, Hashable) and not isinstance(arg, NDArrayOperatorsMixin) for arg in kwargs.values() ) if not hash_a or not hash_kw: obj = object.__new__(cls) obj.__cache_key__ = (cls, args, kwargs) # type: ignore return obj key = (cls, args, tuple(kwargs.items())) _instances = cls._instances # type: ignore if _instances.get(key, None) is None: _logger.debug( ( 'Creating cached instance for class: %s,' ' with args %s, and kwargs %s' ) % (cls.__name__, args, kwargs), ) _instances[key] = object.__new__(cls) _instances[key].__cache_key__ = (cls, args, kwargs) return _instances[key] def __copy__(self) -> CachedClass: return self def __deepcopy__(self, memo: Any) -> CachedClass: return self.__copy__() def __getnewargs_ex__(self) -> tuple[Any, Any]: return self.__cache_key__[1], self.__cache_key__[2] # type: ignore