【问题标题】:Python: How to specify function return type in a mixin methodPython:如何在 mixin 方法中指定函数返回类型
【发布时间】:2023-03-17 11:13:01
【问题描述】:

我正在尝试准确地注释从 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 为键的普通字典,而不在名为 @987654334 的数据类中创建单个属性@。所以其中有一些,它们都有一个名为storedict,所以我想我会使用collections.abc.MutableMapping 来允许我通过下标访问store,例如twos["a"]。因此,我编写了 mixin 来做到这一点,但如果我不需要,很遗憾失去所有类型。

感谢大家的指点 :)

【问题讨论】:

    标签: python python-3.x mypy


    【解决方案1】:

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

    【讨论】:

    • 哦,太好了,谢谢!我看到我需要如何在类定义中实例化类型变量。以前我真的不明白。但是,有没有办法从存储变量本身获取 ThingOne/ThingTwo 类型。超类在定义时知道它是哪一个。无论如何,您的更改已经使它现在可以工作并且还修复了一些ones["a"] = ... 类型错误二,因为我认为它现在知道应该在该字典中放入什么。
    猜你喜欢
    • 2021-07-22
    • 2019-06-23
    • 2022-12-19
    • 1970-01-01
    • 2023-01-08
    • 1970-01-01
    • 1970-01-01
    • 2015-03-23
    • 1970-01-01
    相关资源
    最近更新 更多