定义typing.Dict和dict的区别是什么?

273

我正在练习在Python 3.5中使用类型提示。我的其中一位同事使用typing.Dict

import typing


def change_bandwidths(new_bandwidths: typing.Dict,
                      user_id: int,
                      user_name: str) -> bool:
    print(new_bandwidths, user_id, user_name)
    return False


def my_change_bandwidths(new_bandwidths: dict,
                         user_id: int,
                         user_name: str) ->bool:
    print(new_bandwidths, user_id, user_name)
    return True


def main():
    my_id, my_name = 23, "Tiras"
    simple_dict = {"Hello": "Moon"}
    change_bandwidths(simple_dict, my_id, my_name)
    new_dict = {"new": "energy source"}
    my_change_bandwidths(new_dict, my_id, my_name)

if __name__ == "__main__":
    main()

两者都可以正常工作,似乎没有区别。

我已经阅读了typing模块文档

typing.Dictdict之间,在程序中应该使用哪一个?


19
请注意,Python实际上并不强制执行类型提示。它们只是提示,在运行时甚至编译时都不会使用来强制类型。虽然Python是强类型(与弱类型相反),但它也是动态类型(与严格类型相反)。请参见Python是否是强类型语言?。外部工具如mypy可以利用这些提示来帮助您编写更好的代码,这个过程称为静态分析。 - Martijn Pieters
3
@MartijnPieters 我曾经喜欢在我的代码中使用类型提示,结合MyPy一起使用,假装我可以在Python中实现类型安全。不幸的是,这让我遇到了两个问题:A)代码不能在 < 3.4 版本上运行;B)人们嘲笑我,因为显然,类型提示是个笑话。真的很不幸。 - cat
21
@cat:类型提示是由一位Facebook员工引入Python的,因为我们在将同样的功能添加到PHP中取得了巨大的成功(参见hack)。任何嘲笑这个功能的人都没有建立过超过几个工程师的大型项目。 - Martijn Pieters
3
不,def a(b: int) -> bool: 在Python 2.7中是语法错误,我认为在早期版本的Python 3中也是语法错误。 - cat
3
@cat:你在谈论函数注释,这是Python 3.0添加的语法。因此,唯一一个会出现语法错误的版本是2.7,这就是为什么mypy支持将该信息放在注释中的原因。 - Martijn Pieters
显示剩余3条评论
4个回答

332

使用普通的dicttyping.Dict没有实质性的区别,不过typing.Dict是一种泛型类型*,它让你也可以指定键和值的类型,因此更加灵活:

def change_bandwidths(new_bandwidths: typing.Dict[str, str],
                      user_id: int,
                      user_name: str) -> bool:

因此,在您的项目生命周期的某个时刻,您可能希望更精确地定义字典参数,在这种情况下,将typing.Dict扩展为typing.Dict[key_type, value_type]比替换dict更“小”。

通过在此处使用MappingMutableMapping类型,您甚至可以使其更加通用;由于您的函数不需要更改映射,因此我建议使用Mappingdict是一种映射,但是您还可以创建其他满足映射接口的对象,并且您的函数可能仍然适用于这些对象:

def change_bandwidths(new_bandwidths: typing.Mapping[str, str],
                      user_id: int,
                      user_name: str) -> bool:
现在你明确地告诉其他用户,该函数不会实际更改传入的 new_bandwidths 映射。
你实际上只是期望一个可打印的对象。这可能是测试实现,但就目前而言,如果使用 new_bandwidths: typing.Any,您的代码将继续工作,因为 Python 中的任何对象都是可打印的。


*: 注意:如果您使用的是 Python 3.7 或更高版本,则可以在模块开头使用 from __future__ import annotations 将 dict 用作泛型类型;而在 Python 3.9 中,dict(以及其他标准容器)即使没有该指令,也支持被用作泛型类型。

2
有用的附加示例是当字典值可以是不同类型时,例如 {"name": "bob", "age" : 51},是否类似于 typing.Mapping[Union[str, int]]?那么像 {"person": {"name":"bob", "age": 51} 这样的嵌套字典会是 typing.Mapping[str, typing.Mapping[Union[str, int]]] 吗?像这样使用 Union 让我感到困扰,因为它不是一个严格的模式,因为没有排序。也许这没关系,或者有其他选择? - Davos
1
不用在意关于 Union 的问题,我看到它仍然是一个未解决的讨论 https://github.com/python/typing/issues/28 - Davos
2
这似乎非常有趣、有用且相关 https://www.python.org/dev/peps/pep-0589/ - Greg Hilston
2
@GregHilston:啊,是的,没错。 - Martijn Pieters
4
根据打字文档中的示例,dict[str, str]也是有效的,参见:https://docs.python.org/3/library/typing.html#type-aliases - haridsv
显示剩余8条评论

40

typing.Dict 是字典 dict 的一种通用版本:

class typing.Dict(dict, MutableMapping[KT, VT])

这是字典的一种通用版本。使用此类型的方法如下:

def get_position_in_index(word_list: Dict[str, int], word: str) -> int:
     return word_list[word]
在这里您可以指定字典中键和值的类型:Dict[str, int]

15

如在Python官方文档中所述:

class typing.Dict(dict, MutableMapping[KT, VT])

dict的通用版本。用于注释返回类型。若要注释参数,建议使用抽象集合类型,例如Mapping。

可按以下方式使用此类型:

def count_words(text: str) -> Dict[str, int]:
    ...

但是dict不够通用,您可以更改传入的映射。实际上,在python.Dict中,您可以指定更多详细信息。

另一个提示:

自3.9版本以后已弃用:builtins.dict现在支持[]。请参见PEP 585和通用别名类型。


6
指出 typing.Dict 已被弃用是非常好的。 - jrc

7
如果您在谷歌上搜索 TypeError: Too few parameters for typing.Dict; actual 1, expected 2,则需要为键和值都提供类型。因此,应该使用Dict[str, str] 而不是Dict[str]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接