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)
Mypy(以及一般的 PEP 484)的设计使得在最理想的情况下,您只需要向代码的“边界”或“接口”添加类型注释。
例如,您基本上必须在以下位置添加注释/类型元数据:
class MyClass(Dict[int, str]): ...,而不是class MyClass(dict): ...。这些都是代码“边界”的示例。参数/返回类型的类型提示让函数的调用者确保他们正确调用它,字段的类型提示让调用者知道他们正在正确使用对象,等等......
Mypy(和其他 PEP 484 兼容工具)将使用该信息并尝试推断其他所有内容的类型。这种行为旨在粗略地模仿人类阅读代码的方式:例如,一旦您知道传入的是什么类型,通常很容易理解其余代码的作用。
毕竟,Python 是一种从一开始就被设计为可读的语言!我们不需要到处散布类型提示来增强我们对代码功能的理解。
当然,mypy(以及其他符合 PEP 484 的工具)并不完美,有时它们可能无法正确推断某些局部变量的类型。在这种情况下,您可能需要添加一个类型提示来帮助 mypy。Ethan 的回答很好地概述了一些需要注意的常见情况。(有趣的是,这些案例也往往是人类读者可能难以理解您的代码的例子!)
因此,将所有内容放在一起,一般建议是:
所以,回到你的例子,你会不会在这两种情况下添加类型提示。人类读者和 mypy 都可以判断您的_volume字段必须是浮点数:很明显必须是这种情况,因为参数是一个浮点数,并且将浮点数乘以 int 总是会产生另一个浮点数。
同样的,你会不会注释添加到您的my_volume变量。因为return_volume()有类型提示,所以很容易查看它返回my_volume的类型并理解它是 float 类型。(如果你犯了一个错误并且不小心认为它不是浮点数,那么 mypy 会为你捕捉到它。)
Mypy 做了一些非常高级的类型推断。通常,您不需要注释变量。mypy 文档 [1] 中提到了推理:
Mypy 将初始赋值视为变量的定义。如果没有明确指定变量的类型,mypy会根据值表达式的静态类型推断类型
一般的经验法则是“注释其类型在初始分配时不可推断的变量”。
这里有些例子:
空容器。如果我定义a为a = [],mypy 将不知道列表中哪些类型是有效的a。
Optional类型。通常,如果我定义一个Optional类型,我会将变量分配给None. 例如,如果我这样做a = None,mypy 会推断它a具有 type NoneType,如果您想稍后分配a给5它,则需要对其进行注释:a: Optional[int] = None。
复杂的嵌套容器。例如,如果您有一个同时包含列表值和字符串值的字典,例如 mypy 可能会推断Dict[str, Any]. 您可能需要对其进行注释以使其更准确。
当然还有更多的案例。
在您的示例中, mypy 可以推断表达式的类型。
[1] https://mypy.readthedocs.io/en/latest/type_inference_and_annotations.html
| 归档时间: |
|
| 查看次数: |
1086 次 |
| 最近记录: |