问题描述
我正在尝试准确注释 mixin 方法的返回类型。
下面的最小示例:
from dataclasses import dataclass,field
from typing import Dict,Protocol
class Hasstore(Protocol):
store: dict
class StoreGetMixin:
def __getitem__(self: Hasstore,key: str): # what to put in -> type?
return self.store[key]
@dataclass
class ThingOne:
size: int
@dataclass
class ThingTwo:
name: str
@dataclass
class Ones(StoreGetMixin):
store: Dict[str,ThingOne] = field(default_factory=dict)
@dataclass
class Twos(StoreGetMixin):
store: Dict[str,ThingTwo] = field(default_factory=dict)
ones = Ones()
ones.store = {"a": ThingOne(1),"b": ThingOne(2)}
one = ones["a"] # <- this should be typed as a ThingOne
twos = Twos()
twos.store = {"a": ThingTwo("one"),"b": ThingTwo("two")}
two = twos["a"] # <- this should be typed as a ThingTwo
所以我正在尝试编写一个可重用的 mixin,它可以访问各种数据类中的 store
字典。但我不知道如何告诉 __getitem__
方法它返回的是什么类型。
我见过输入 self
的示例,但在这种情况下我需要输入 self.store
。 mypy 可以将 self.store
的类型视为 dict
(我假设它来自 Hasstore
)但它不知道键或值类型。
这可能吗?
我是否需要更好地注释 Hasstore
协议的 store
?我尝试过,例如 dict[str,T]
,但我无法使其工作,因为 T
如果像这样使用则不会被实例化。
我这样做的原因是使用 Mashumaro 将我的数据类序列化为 JSON,我无法弄清楚如何存储一个以 str
为键的普通字典而不在名为的数据类中创建单个属性store
。所以有一些,它们都有一个名为 dict
的 store
所以我想我会使用 collections.abc.MutableMapping
来允许我通过下标访问 store
,例如,twos["a"]
。因此,我编写了mixin来做到这一点,但如果我不需要的话,丢失所有类型很遗憾。
感谢各位指点:)
解决方法
通用协议应该可以工作(文档在这里:https://mypy.readthedocs.io/en/stable/generics.html#generic-protocols):
T = TypeVar('T')
class HasStore(Protocol[T]):
store: Dict[str,T]
class StoreGetMixin(HasStore[T]):
def __getitem__(self,key: str) -> T: # what to put in -> type?
return self.store[key]
@dataclass
class ThingOne:
size: int
@dataclass
class ThingTwo:
name: str
@dataclass
class Ones(StoreGetMixin[ThingOne]):
store: Dict[str,ThingOne] = field(default_factory=dict)
@dataclass
class Twos(StoreGetMixin[ThingTwo]):
store: Dict[str,ThingTwo] = field(default_factory=dict)
ones = Ones()
ones.store = {"a": ThingOne(1),"b": ThingOne(2)}
one = ones["a"] # <- this should be typed as a ThingOne
reveal_type(one)
twos = Twos()
twos.store = {"a": ThingTwo("one"),"b": ThingTwo("two")}
two = twos["a"] # <- this should be typed as a ThingTwo
reveal_type(two)
输出为:
note: Revealed type is 'experiment.ThingOne*'
note: Revealed type is 'experiment.ThingTwo*'