ale*_*xcs 3 python metaclass mypy python-typing
我有一个单例的 Python (3.8) 元类,如下所示
我尝试添加如下类型:
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]
Run Code Online (Sandbox Code Playgroud)
在行中:
_instances: Dict[Any, _T] = {}
Run Code Online (Sandbox Code Playgroud)
MyPy 警告:
Mypy: Type variable "utils.singleton._T" is unbound
我已经尝试了不同的迭代,但没有成功;我很难弄清楚如何输入这个字典。
此外,该行:
_instances: Dict[Any, _T] = {}
Run Code Online (Sandbox Code Playgroud)
生产:
Mypy: The erased type of self "Type[golf_ml.utils.singleton.Singleton]" is not a supertype of its class "golf_ml.utils.singleton.Singleton"
我怎样才能正确输入这个?
这应该有效:
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]
Run Code Online (Sandbox Code Playgroud)
粗略解释:
_T = TypeVar("_T", bound="Singleton")不正确 -Singleton是type(type(obj))哪里obj: _T = Singleton.__call__(...)。在正确的使用中, 的参数bound=只能是type(obj)或一些联合类型构造,而不是type(type(obj)。Type variable "_T" is unbound表示您需要使绑定Singleton变得通用。_T_TThe erased type of self ...错误消息告诉您您已经“删除”了类型检查器的推断类型* cls。从技术上讲,__call__元类上的方法与任何其他实例方法相同 - 第一个参数只是所属类的类型。然而,在当前的静态类型系统中,元类的实例方法的第一个参数与type[...].*推断的类型明确
Self如下:Run Code Online (Sandbox Code Playgroud)import typing as t Self = t.TypeVar("Self", bound="A") class A: def instancemethod(arg: Self) -> None: pass @classmethod def classmethod_(arg: type[Self]) -> None: pass
运行时也很重要,因此最终的健全性检查是确保您实际上已经使用此元类实现了单例:
class Logger(metaclass=Singleton):
pass
>>> print(Logger() is Logger())
True
Run Code Online (Sandbox Code Playgroud)