如何为 Mypy 类型注释指定 OrderedDict K,V 类型?

Posted

技术标签:

【中文标题】如何为 Mypy 类型注释指定 OrderedDict K,V 类型?【英文标题】:How do I specify OrderedDict K,V types for Mypy type annotation? 【发布时间】:2017-05-03 14:12:41 【问题描述】:

我正在使用 Python 3.5 和 Mypy 对我的脚本进行一些基本的静态检查。最近我重构了一些返回 OrderedDict 的方法,但是当我尝试使用指定了 Key 和 Value 类型的返回注解时遇到了“'type' object is not subscriptable”错误。

简化示例:

#!/usr/bin/env python3.5

from collections import OrderedDict

# this works
def foo() -> OrderedDict:
    result = OrderedDict() # type: OrderedDict[str, int]
    result['foo'] = 123
    return result

# this doesn't
def foo2() -> OrderedDict[str, int]:
    result = OrderedDict() # type: OrderedDict[str, int]
    result['foo'] = 123
    return result

print(foo())

这是运行时的python输出:

Traceback (most recent call last):
  File "./foo.py", line 12, in <module>
    def foo2() -> OrderedDict[str, int]:
TypeError: 'type' object is not subscriptable

然而,Mypy 对注释中的类型注释没有问题,如果我尝试执行 result[123] = 123,实际上会发出警告。

这是什么原因造成的?

【问题讨论】:

现在可以使用(mypy 版本 0.501)。 仅存入修复链接:bugs.python.org/issue35341 【参考方案1】:

mypy 中没有问题(至少在 0.501 中没有)。 但是 Python 3.6.0 存在问题。 考虑以下几点:

from collections import OrderedDict
from typing import Dict

def foo() -> Dict[str, int]:
    result: OrderedDict[str, int] = OrderedDict()
    result['two'] = 2
    return result

此代码将同时满足 mypy (0.501) 和 Python (3.6.0)。 但是,如果您将Dict 替换为OrderedDict,那么mypy 仍然会很高兴,但执行它会以TypeError: 'type' object is not subscriptable 结束。

有趣的是,Python 解释器在函数签名中看到下标 OrderedDict 时会死掉,但很高兴在变量类型注释中接受它。

无论如何,我的解决方法是在函数签名中使用 Dict 而不是 OrderedDict(并添加注释,如果/当 Python 解释器将学会接受正确的签名时,应该修复此问题) .

【讨论】:

是的,我最终在自己的代码中使用了相同的解决方法。 这导致 mypy 0.063 出现错误,但建议将函数签名更改为字符串的答案有效。 Python 3.7.2 introduces typing.OrderedDict 在 3.7.2 中引入的 typing.OrderedDict 在 3.9 中再次被弃用,增加了对 collections.OrderedDict[K, V] 的支持。 另一种解决方法是在函数签名中引用类型,例如'OrderedDict[...]'【参考方案2】:

作为一种变通方法,您还可以将返回类型放入字符串中以满足 Mypy 和 Python 3.6 的要求:

from collections import OrderedDict

def foo() -> 'OrderedDict[str, int]':
    result = OrderedDict()
    result['foo'] = 123
    return result

【讨论】:

【参考方案3】:

您还可以尝试使用MutableMapping(例如在此答案中:https://***.com/a/44167921/1386610)

from collections import OrderedDict
from typing import Dict

def foo() -> MutableMapping[str, int]:
    result = OrderedDict() # type: MutableMapping[str, int]
    result['foo'] = 123
    return result

【讨论】:

【参考方案4】:

我不知道哪个版本允许这样做,但是对于 2021 年 3 月 24 日的更好的解决方案,已针对 Python 3.7.5 进行了测试:

from collections import OrderedDict
import typing

def foo() -> typing.OrderedDict[str, int]:
    result: typing.OrderedDict[str, int] = OrderedDict()
    result['two'] = 2
    return result

享受所有世界!

【讨论】:

对于 3.7,我尝试了suggestions: OrderedDict[str, Any] = OrderedDict(),但在OrderedDict() 下方有一个红色波浪线表示Generics should be specified through square brackets。但是简单地将 () 替换为 [] 并不能解决问题,因为现在它需要 [] 中的表达式。不确定我是否理解这个问题。 @perennial_noob 请准确写出出现错误的代码。另外,您使用的是 3.7.5+ 吗? 我实际上使用的是 3.8.7。是的,所以我正在使用 Pycharm,它建议使用 [] 修复。我点击它让它修复它,但现在它需要一个表达式。不确定我是否应该使用像 suggestions: OrderedDict[str, Any] = OrderedDict[dummykey] 这样的 None 来初始化一个值,我什至尝试过 suggestions: OrderedDict[str, Any] = 但随后 linter 警告它期待 OrderedDict 但得到了一个 Dict。 试试suggestions: OrderedDict[str, Any] = OrderedDict()suggestions[dummykey] = 1

以上是关于如何为 Mypy 类型注释指定 OrderedDict K,V 类型?的主要内容,如果未能解决你的问题,请参考以下文章

从用mypy注释的python函数返回None,多种返回类型

将 mypy 的通用 self 与 python2 类型注释一起使用

类装饰器上的 Mypy 注释

如何为注释类型编码可选的默认注释值

如何为 React 钩子(useState 等)做流类型注释?

如何为多个组绘制带有注释的堆叠条