定义type.Dict和dict之间的区别?


105

我正在练习在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哪一个,我应该在程序中使用?


11
请注意,Python实际上并不强制执行类型提示。它们只是提示,它们在运行时甚至编​​译时都不用于强制类型。Python可能是强类型的(与弱类型相反),也可能是动态类型的(与严格类型相反)。请参阅Python是否为强类型?。但是,在称为“静态分析”的过程中,诸如mypy之类的外部工具可以使用这些提示帮助您编写更好的代码。
马丁·彼得斯

1
@MartijnPieters我曾经喜欢在代码中与MyPy一起使用类型提示,并假装我可以将Python与类型安全一起使用。不幸的是,它使我A)无法在<3.4上运行的代码,以及B)人们嘲笑我,因为显然,类型提示是笑柄。真的很不幸。

3
@cat:Facebook员工将类型提示引入Python,因为我们在向PHP添加相同功能方面取得了巨大的成功(请参阅hack)。从来没有人笑过,没有多少工程师与任何人进行过一个大型项目。
马丁·彼得

3
@MartijnPieters不,这def a(b: int) -> bool:是Python 2.7中的语法错误,我认为这也是旧版Python 3中的语法错误。

1
@cat:您在这里谈论的是函数注释,这是添加到Python 3.0中的语法。因此,唯一存在语法错误的版本是2.7,这就是为什么mypy支持将该信息放入注释中的原因。
马丁·彼得斯

Answers:


147

使用Plaintyping.DictdictNo之间没有真正的区别。

然而,typing.Dict是一种通用型 *,可让您指定键和值的类型太多,使之更加灵活:

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

因此,很可能是在项目生命周期中的某个时候,您希望更精确地定义字典参数,在这一点上,扩展typing.Dicttyping.Dict[key_type, value_type]而不是替换是“更小的”改变dict

您可以通过在此处使用MappingMutableMapping类型来使其更通用。由于您的函数不需要更改映射,因此我坚持使用Mapping。Adict是一个映射,但是您可以创建也满足映射接口的其他对象,并且您的函数可能仍可以与那些对象一起使用:

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或更高版本,则使用dict开头的模块即可将其用作通用类型from __future__ import annotations,而从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使我感到烦恼,因为它不是严格的架构,因为没有排序。也许还可以,或者有其他选择吗?
达沃斯

1
没关系,Union我仍然认为这是一个公开讨论的问题github.com/python/typing/issues/28
Davos

1
这似乎非常有趣,有用且相关python.org/dev/peps/pep-0589
Greg Hilston '19年

@GregHilston:实际上是关于如何限制字典可以包含哪些键,以及指定每个关联值应具有的类型。
马丁·彼得斯

1
@GregHilston:啊,是的。
的Martijn Pieters的

26

typing.Dict是以下内容的通用版本dict

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

dict的通用版本。此类型的用法如下:

def get_position_in_index(word_list: Dict[str, int], word: str) -> int:
     return word_list[word]

在这里,您可以在dict中指定键和值的类型: Dict[str, int]

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.