Advertisements
I have a Python (3.8) metaclass for a singleton as seen here
I’ve tried to add typings like so:
from typing import Dict, Any, TypeVar, Type
_T = TypeVar("_T", bound="Singleton")
class Singleton(type):
_instances: Dict[Any, _T] = {}
def __call__(cls: Type[_T], *args: Any, **kwargs: Any) -> _T:
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
In the line:
_instances: Dict[Any, _T] = {}
MyPy warns:
Mypy: Type variable "utils.singleton._T" is unbound
I’ve tried different iterations of this to no avail; it’s very hard for me to figure out how to type this dict.
Further, the line:
def __call__(cls: Type[_T], *args: Any, **kwargs: Any) -> _T:
Produces:
Mypy: The erased type of self "Type[golf_ml.utils.singleton.Singleton]" is not a supertype of its class "golf_ml.utils.singleton.Singleton"
How could I correctly type this?
>Solution :
This should work:
from __future__ import annotations
import typing as t
_T = t.TypeVar("_T")
class Singleton(type, t.Generic[_T]):
_instances: dict[Singleton[_T], _T] = {}
def __call__(cls, *args: t.Any, **kwargs: t.Any) -> _T:
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
Rough explanations:
_T = TypeVar("_T", bound="Singleton")
is not correct –Singleton
istype(type(obj))
whereobj: _T = Singleton.__call__(...)
. In proper usage, the argument tobound=
can only betype(obj)
or some union typing construct, nottype(type(obj)
.Type variable "_T" is unbound
indicates that you need to makeSingleton
generic with respect to_T
to bind_T
.The erased type of self ...
error message is telling you that you’re committing an error that will go away once you fix (1).
Runtime is important too, so the final sanity check is to make sure you’ve actually implemented a singleton using this metaclass:
class Logger(metaclass=Singleton):
pass
>>> print(Logger() is Logger())
True