类型提示:何时进行注释

JPF*_*oia 7 python type-hinting mypy

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

前任:

def assign_volume(self, volume: float) -> None:
    self._volume = volume * 1000
Run Code Online (Sandbox Code Playgroud)

我应该写吗

self._volume: float = volume *1000
Run Code Online (Sandbox Code Playgroud)

在这种情况下?

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

def return_volume(self) -> float:
        return self._volume
Run Code Online (Sandbox Code Playgroud)

在我的代码中的某处:

my_volume = return_volume()
Run Code Online (Sandbox Code Playgroud)

我应该写:

my_volume: float = return_volume()
Run Code Online (Sandbox Code Playgroud)

Mic*_*x2a 9

Mypy(以及一般的 PEP 484)的设计使得在最理想的情况下,您只需要向代码的“边界”或“接口”添加类型注释。

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

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

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

Mypy(和其他 PEP 484 兼容工具)将使用该信息并尝试推断其他所有内容的类型。这种行为旨在粗略地模仿人类阅读代码的方式:例如,一旦您知道传入的是什么类型,通常很容易理解其余代码的作用。

毕竟,Python 是一种从一开始就被设计为可读的语言!我们不需要到处散布类型提示来增强我们对代码功能的理解。

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

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

  1. 向代码的所有“边界”添加类型提示,例如函数参数和返回类型。
  2. 默认注释变量。如果 mypy 无法推断某个变量应该是什么类型,请添加一个注释来帮助它。
  3. 如果您发现自己需要注释大量变量以使 mypy 满意,请考虑重构您的代码。如果 mypy 很容易混淆,那么人类读者也可能很容易混淆。

所以,回到你的例子,你会不会在这两种情况下添加类型提示。人类读者和 mypy 都可以判断您的_volume字段必须是浮点数:很明显必须是这种情况,因为参数是一个浮点数,并且将浮点数乘以 int 总是会产生另一个浮点数。

同样的,你会不会注释添加到您的my_volume变量。因为return_volume()有类型提示,所以很容易查看它返回my_volume的类型并理解它是 float 类型。(如果你犯了一个错误并且不小心认为它不是浮点数,那么 mypy 会为你捕捉到它。)


eth*_*nhs 6

Mypy 做了一些非常高级的类型推断。通常,您不需要注释变量。mypy 文档 [1] 中提到了推理:

Mypy 将初始赋值视为变量的定义。如果没有明确指定变量的类型,mypy会根据值表达式的静态类型推断类型

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

这里有些例子:

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

  • Optional类型。通常,如果我定义一个Optional类型,我会将变量分配给None. 例如,如果我这样做a = None,mypy 会推断它a具有 type NoneType,如果您想稍后分配a5它,则需要对其进行注释:a: Optional[int] = None

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

当然还有更多的案例。

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

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