【问题标题】:How can I type hint the return type of .values() in a custom dict subclass?如何在自定义 dict 子类中键入提示 .values() 的返回类型?
【发布时间】:2021-10-15 17:20:12
【问题描述】:

当我使用mypy 键入检查以下类时,它会引发错误

错误:从声明为返回“Optional[SomeDictValueType]”的函数返回 Any

get_by_id 中,.values() 的类型未正确定义/限制。

class SomeDict(dict):
    def __init__(self) -> None:
        self._some_attribute: SomeRandomType = None

    def get_by_id(self, id: str) -> Optional[SomeDictValueType]:
        for p in self.values():
            if p._id == id:
                return p
        return None

我在网上找到了类似的问题,并尝试了以下方法:
  1. __setitem__ 添加类型提示,如here 所述

     def __setitem__(self, key: str, value: SomeDictValueType) -> None:
         super(SomeDict, self).__setitem__(key, value)
    
  2. 在类头中使用Mapping 解释here

     class SomeDict(dict, Mapping[str, SomeDictValueType]): ...
    

如果不使用# type: ignore,我怎样才能摆脱这个错误?此类的实例永远不会保存SomeDictValueType 以外的类型的值。


编辑:
这是重现错误的简约示例。将以下代码sn-p保存到python文件中,在上面执行mypy --strict <filename>.py

from typing import Optional

class SomeDict(dict):  # type: ignore
    def __init__(self) -> None:
        self._some_attribute: Optional[str] = None

    def get_by_id(self, id: str) -> Optional[int]:
        for p in self.values():
            if p._id == id:
                return p
        return None

应该抛出以下错误:

test.py:10:错误:从声明返回的函数返回任何 "可选[int]"

【问题讨论】:

  • 如果不知道SomeRandomTypeSomeDictValueType 的定义是什么(或者它们可能是什么,就很难测试这个问题的可能解决方案,至少)。如果您可以编辑您的问题以提供一个最小的、可重复的示例,那将会很有帮助。 stackoverflow.com/help/minimal-reproducible-example
  • @AlexWaygood SomeRandomType 不会以任何方式影响问题,对此感到抱歉。为了方便起见,我只想在示例中包含__init__SomeDictValueType 可以是你想要的任何东西,你会得到同样的错误。但我将在 EDIT 部分提供一个简单的错误示例;)
  • 试着从潜在的回答者的角度来考虑——如果我们不能自己测试代码,我们不知道SomeRandomType 的定义是否重要;)
  • 是的,很抱歉 ^^' 我写问题太快了。
  • 您现在已经解决了您的问题,但请注意以后的问题 - 您的示例仍然不完整,因为我们不知道要在此字典中存储哪些值以便它们可以保证所有人都有_id 属性。一个示例用例会很有用。

标签: python mypy


【解决方案1】:

mypy 是正确的。由于您遍历values(),它无法判断dict值的类型是什么,它认为它是Any

【讨论】:

  • 是的,但就我而言,该类永远不会与SomeDictValueType 以外的其他类型一起使用。这就是我要强制执行类型的原因。
  • @c0mr4t - 所以不要扩展字典。使用Dict[str,SomeDictValueType] 并使get_by_id 成为一个实用函数
【解决方案2】:

我想,我只是想通了。我认为您不能从打字定义中继承(我在开始时尝试过一次,但出现另一个错误并且看起来不够接近)。
在我看来,以下 sn-p 将是最简单的错误重现示例的解决方案。

from typing import Optional, Dict

class SomeDict(Dict[str, int]):
    def __init__(self) -> None:
        self._some_attribute: Optional[str] = None

    def get_by_id(self, id: str) -> Optional[int]:
        for p in self.values():
            if p == 5:
                return p
        return None

【讨论】:

  • 是的,这是正确的解决方案,我只是自己写出来的。问题是,如果您从未参数化的dict 继承,MyPy 会将其解释为dict[Any, Any],因此返回字典值之一的方法必须返回Any。从参数化的dict 继承可以解决这个问题。
猜你喜欢
  • 2016-08-17
  • 1970-01-01
  • 2020-03-18
  • 2021-09-17
  • 2021-02-11
  • 1970-01-01
  • 1970-01-01
  • 2022-01-23
  • 2019-07-19
相关资源
最近更新 更多