代码之家  ›  专栏  ›  技术社区  ›  JPFrancoia

类型提示:何时注释

  •  2
  • JPFrancoia  · 技术社区  · 6 年前

    我越来越多地使用类型提示和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 回复  |  直到 6 年前
        1
  •  3
  •   ethanhs    6 年前

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

    mypy将初始赋值视为变量的定义。如果未显式指定变量的类型,mypy将根据值表达式的静态类型推断该类型

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

    下面是一些例子:

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

    • Optional 类型。通常,如果我定义 可选的 输入,我将把变量分配给 None 是的。例如,如果我这样做了 a = None ,Mypy会推断 具有类型 NoneType ,如果要分配 5 稍后,您需要对其进行注释: a: Optional[int] = None 是的。

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

    当然还有更多的案例。

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

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

        2
  •  3
  •   Michael0x2a    6 年前

    mypy(通常是pep 484)的设计是为了在最理想的情况下,只需要向代码的“边界”或“接口”添加类型注释。

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

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

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

    mypy(和其他符合pep 484的工具)将使用这些信息并尝试 推断 其他一切的类型。这种行为被设计成大致模仿人类阅读代码的方式:例如,一旦知道传入的类型,通常很容易理解其余代码的作用。

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

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

    因此,综合考虑,总的建议是:

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

    所以,回到你的例子,你会 在两种情况下都添加类型提示。一个人类读者和Mypy都能看出 _volume field必须是float:很明显,必须是这种情况,因为参数是float,将float乘以int总是会产生另一个float。

    同样的,你会 将批注添加到 my_volume 变量。自从 return_volume() 有类型提示,很容易看到返回的类型并理解 我的音量 类型为float。(如果你犯了一个错误,不小心以为那是另一个东西,那么mypy会帮你抓住它。)

        3
  •  1
  •   Bierbarbar    6 年前

    对我来说,它开始在任何可能的地方编写类型提示。它一点也不慢,如果您在功能中返回到以前的代码,则会更容易。因此,现在除了python文件的大小之外,尽可能多地使用它们是一个消极的方面。