类型提示:何时注释

时间:2018-07-06 12:55:47

标签: python type-hinting mypy

我越来越多地使用类型提示和mypy。但是,对于何时应该显式注释声明以及何时可以由mypy自动确定类型,我有一些疑问。

例如:

def assign_volume(self, volume: float) -> None:
    self._volume = volume * 1000

我应该写

self._volume: float = volume *1000

在这种情况下?

现在,如果我具有以下功能:

def return_volume(self) -> float:
        return self._volume

在我的代码中的某处:

my_volume = return_volume()

我应该写:

my_volume: float = return_volume()

3 个答案:

答案 0 :(得分:3)

Mypy进行了一些非常高级的类型推断。通常,您不需要注释变量。 mypy文档[1]关于推理的内容:

  

Mypy将初始分配视为变量的定义。如果您未明确指定变量的类型,则mypy将根据值表达式的静态类型来推断类型

通常的经验法则是“注释类型在初始分配时不可推断的变量”。

以下是一些示例:

  • 空容器。如果我将a定义为a = [],mypy将不知道列表a中有效的类型。

  • Optional类型。通常,如果我定义了Optional类型,我会将变量分配给None。例如,如果我执行a = None,mypy将推断出a的类型为NoneType,如果您以后想将a分配给5,则需要对其进行注释:a: Optional[int] = None

  • 复杂的嵌套容器。例如,如果您有一个既包含列表值又包含字符串值的字典,则mypy可能会推断出Dict[str, Any]。您可能需要对其进行注释才能更加准确。

当然还有更多的情况。

在您的示例中,mypy可以推断表达式的类型。

[1] https://mypy.readthedocs.io/en/latest/type_inference_and_annotations.html

答案 1 :(得分:3)

设计Mypy(通常是PEP 484)的目的是,在最理想的情况下,您只需要在代码的“边界”或“接口”中添加类型注释即可。

例如,您基本上必须在以下位置添加注释/类型元数据:

  1. 函数和方法的参数和返回类型。
  2. 任何对象字段(假设仅通过查看构造函数就无法推断出字段的类型)
  3. 继承类时。例如,如果您特别想将int字典归为strs,则应该执行class MyClass(Dict[int, str]): ...,而不是class MyClass(dict): ...

这些都是代码“边界”的示例。在参数/返回类型上的类型提示使函数的调用者可以确保它们正确地调用它,在字段上的类型提示可以使调用者知道它们正确地使用了对象,等等。

然后,

Mypy(以及其他符合PEP 484的工具)将使用该信息,并尝试推断其他所有类型。此行为旨在大致模拟人类如何阅读代码:例如,一旦知道传入的类型,通常很容易理解其余代码的作用。

毕竟,Python是一种从一开始就被设计为易于阅读的语言!我们不需要在所有地方分散类型提示来增强对代码功能的理解。

当然,mypy(和其他符合PEP 484的工具)并不完美,有时它们可​​能无法正确推断某些局部变量的类型。在这种情况下,您可能需要添加类型提示来帮助mypy。 Ethan's answer很好地概述了一些需要注意的常见情况。 (有趣的是,这些情况也往往是人类读者可能难以理解您的代码的示例!)

因此,将所有内容放在一起,通常的建议是:

  1. 向代码的所有“边界”添加类型提示,例如函数参数和返回类型。
  2. 默认为 not 注释变量。如果mypy无法推断某些变量应为哪种类型,请添加注释以帮助它。
  3. 如果发现自己需要注释很多变量以使mypy开心,请考虑重构代码。如果mypy很容易混淆,那么人类读者也很容易混淆。

因此,回到您的示例,您将在两种情况下都添加类型提示。普通读者和mypy都可以告诉您_volume字段必须为浮点数:因为参数为浮点数并将浮点数乘以int会始终产生另一个浮点数,因此很明显必须是这种情况。

类似地,您将添加注释到您的my_volume变量中。由于return_volume()具有类型提示,因此很容易查看返回的类型并了解my_volume是float类型。 (而且,如果您犯了一个错误,并且不小心认为是浮动以外的其他东西,那么mypy会帮您抓住它。)

答案 2 :(得分:1)

对于我自己,它开始在可能的任何地方编写类型提示。它一点也不慢,并且如果您返回到该功能中的旧代码,它会变得更加容易。因此,除了python文件的大小之外,现在在尽可能多地使用它们方面存在负面影响。