首页 > 解决方案 > Python:如何在 mixin 方法中指定函数返回类型

问题描述

我正在尝试准确注释 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.storemypy 可以看到self.storeas的类型dict(我假设这来自HasStore),但它不知道键或值类型。

这可能吗?

我需要更好地注释HasStore协议store吗?例如,我试过了,dict[str, T]但我无法让它工作,因为T如果这样使用它就不会被实例化。

我这样做的原因是使用 Mashumaro 将我的数据类序列化为 JSON,我无法弄清楚如何存储一个以 a 为键的普通字典,str而无需在名为store. 所以其中有一些,它们都有一个dict被调用的store,所以我想我会用它collections.abc.MutableMapping来允许我store通过下标访问,例如twos["a"]. 因此,我编写了 mixin 来做到这一点,但如果我不需要,很遗憾失去所有类型。

非常感谢任何指针:)

标签: pythonpython-3.xmypy

解决方案


通用协议应该可以工作(此处的文档: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*'

推荐阅读