Python 代码中的注释、文档字符串和类型提示

程序的源代码应该易于人类阅读。让程序正确运行只是其目的的一半。如果没有适当的代码注释,自己(包括未来的你)很难理解代码背后的原理和意图。这也会使代码无法维护。在Python中,有多种方法可以为代码添加描述,使其更易读或意图更明确。在下文中,我们将了解如何正确使用注释、文档字符串和类型提示来使我们的代码更易于理解。完成本教程后,您将了解到:

  • 如何在Python中正确使用注释
  • 在某些情况下,字符串字面量或文档字符串可以替代注释
  • 什么是Python中的类型提示,它们如何帮助我们更好地理解代码

用我的新书 Python for Machine Learning 快速启动您的项目,其中包括分步教程和所有示例的Python源代码文件。

让我们开始吧。

Python代码中的注释、文档字符串和类型提示。照片来自Rhythm Goyal。保留部分权利。

概述

本教程分为三个部分:

  • 为Python代码添加注释
  • 使用文档字符串
  • 在Python代码中使用类型提示

为Python代码添加注释

几乎所有编程语言都有专门的注释语法。注释会被编译器或解释器忽略,因此它们对程序流程或逻辑没有影响。但有了注释,代码更容易阅读。

在 C++ 等语言中,我们可以使用双斜杠(//)添加“行内注释”,或使用/**/ enclosed 的注释块。然而,在Python中,我们只有“行内”版本,它们由井号(#)引入。

为每一行代码写注释很容易,但这通常是浪费。当人们阅读源代码时,注释很容易吸引他们的注意力,因此过多的注释会分散阅读。例如,以下内容是不必要的且分散注意力的:

像这样的注释只是在重复代码的功能。除非代码晦涩难懂,否则这些注释不会为代码增加任何价值。下面的例子可能是一个特例,其中“ppf”(百分点函数)的名称不如“CDF”(累积分布函数)这个术语广为人知。

好的注释应该说明我们为什么要这样做。我们来看下面的例子:

上面的函数实现了 AdaDelta 算法。在第一行,当我们给变量solution赋值时,我们没有写“在 bounds[:,0] 和 bounds[:,1] 之间随机插值”这样的注释,因为这只是在重复代码。我们说这一行的意图是“生成一个初始点”。同样,对于函数中的其他注释,我们将一个 for 循环标记为梯度下降算法,而不是简单地说迭代一定次数。

在编写注释或修改代码时,一个要记住的重要问题是确保注释准确地描述了代码。如果它们相互矛盾,会令读者感到困惑。那么,我们是否应该将上面示例的第一行注释写成“将初始解设置为下界”,而代码显然是随机化初始解,反之亦然?如果这就是您打算做的,那么您应该同时更新注释和代码。

一个例外是“待办”注释。不时地,当我们有一个改进代码的想法但还没有修改时,我们可能会在代码中添加待办注释。我们也可以用它来标记未完成的实现。例如:

这是一个常见的做法,许多 IDE 会在找到关键字TODO时以不同的方式突出显示注释块。但是,它应该是临时的,我们不应该滥用它作为问题跟踪系统。

总而言之,一些常见的代码注释“最佳实践”如下:

  • 注释不应重述代码,而应解释代码
  • 注释不应引起混淆,而应消除混淆
  • 在不易理解的代码上添加注释;例如,说明非惯用的语法用法,命名正在使用的算法,或解释意图或假设
  • 注释应简洁明了
  • 在注释中保持一致的风格和语言使用
  • 始终优先编写需要额外注释的优秀代码

使用文档字符串

在 C++ 中,我们可能会写一大段注释,例如:

但在Python中,我们没有等同于/**/的定界符,但我们可以使用以下方式编写多行注释:

这样做是有效的,因为Python支持使用三引号(""")跨越多行声明字符串字面量。而代码中的字符串字面量只是一个没有影响的声明字符串。因此,它在功能上与注释没有区别。

我们想要使用字符串字面量的一个原因是注释掉大块代码。例如:

上面的代码是我们在机器学习问题中通过实验可能会开发出来的示例代码。虽然我们在开始时是随机生成了一个数据集(上面调用了make_classification()),但我们可能希望稍后切换到不同的数据集并重复相同的过程(例如,上面的 pickle 部分)。我们不必删除代码块,可以直接注释掉那些行,以便稍后存储代码。虽然它对于最终代码来说不是最佳的,但在开发解决方案时很方便。

Python 中函数下的第一个字符串字面量如果作为注释,则具有特殊用途。在这种情况下,该字符串字面量被称为函数的“文档字符串”(docstring)。例如:

我们可以看到函数下的第一行是字符串字面量,它与注释的作用相同。它使代码更具可读性,但同时我们也可以从代码中检索它。

由于文档字符串的特殊地位,关于如何编写一个合适的文档字符串存在一些约定。

在 C++ 中,我们可以使用 Doxygen 从注释生成代码文档,同样,我们有 Javadoc 用于 Java 代码。Python 中最接近的匹配是 Sphinx 的“autodoc”工具或 pdoc。两者都将尝试解析文档字符串以自动生成文档。

没有标准的编写文档字符串的方法,但通常,我们期望它们能解释函数(或类或模块)的用途以及参数和返回值。一种常见的风格如上所示,这是 Google 所提倡的。另一种风格来自 NumPy。

autodoc 等工具可以解析这些文档字符串并生成 API 文档。但即使这不是目的,拥有一个描述函数性质、函数参数和返回值数据类型的文档字符串肯定能使您的代码更容易阅读。这尤其适用于 Python,与 C++ 或 Java 不同,Python 是一种 **“鸭子类型”** 语言,其中变量和函数参数没有声明特定的类型。我们可以利用文档字符串来明确说明数据类型的假设,以便人们能够更容易地理解或使用您的函数。

想开始学习机器学习 Python 吗?

立即参加我为期7天的免费电子邮件速成课程(附示例代码)。

点击注册,同时获得该课程的免费PDF电子书版本。

在 Python 代码中使用类型提示

自 Python 3.5 以来,允许使用类型提示语法。顾名思义,它的目的是提示类型,仅此而已。因此,即使它看起来是将 Python 引入 Java,也不意味着要限制变量中存储的数据。上面的示例可以用类型提示重写:

在函数中,参数后面可以跟上 : type 语法来明确说明预期的类型。函数的返回值由冒号之前的 -> type 语法标识。实际上,也可以为变量声明类型提示,例如:

类型提示的好处是双重的:我们可以用它来消除一些需要明确描述所用数据类型的注释。我们还可以帮助静态分析器更好地理解我们的代码,从而帮助它们识别代码中的潜在问题。

有时类型可能很复杂,因此 Python 在其标准库中提供了 typing 模块来帮助清理语法。例如,我们可以使用 Union[int,float] 来表示 int 类型或 float 类型,使用 List[str] 来表示一个列表,其中每个元素都是字符串,并使用 Any 来表示任何类型。如下所示:

但是,重要的是要记住,类型提示仅仅是提示。它不对代码施加任何限制。因此,以下代码虽然会让读者感到困惑,但完全没问题:

使用类型提示可以提高代码的可读性。然而,类型提示最重要的好处是允许静态分析器(如 mypy)告诉我们代码是否存在潜在的错误。如果您使用 mypy 处理上面的代码行,我们会看到以下错误:

静态分析器的使用将在另一篇文章中介绍。

为了说明注释、文档字符串和类型提示的用法,下面是一个定义生成器函数的示例,该函数在固定宽度窗口上对 pandas DataFrame 进行采样。这对于训练 LSTM 网络非常有用,其中应提供连续的几个时间步。在下面的函数中,我们从一个随机行开始,然后提取随后的几行。只要我们能够成功获取一个完整的窗口,我们就将其作为样本。一旦收集到足够的样本来构成一个批次,该批次就会被分派。

您应该会发现,如果我们能为函数参数提供类型提示,它会更清晰,这样我们就能知道,例如,data 是一个 pandas DataFrame。但我们在文档字符串中进一步说明,它应该有一个 datetime 索引。我们用注释来描述从输入数据中提取行窗口的算法,以及内部 while 循环中“if”块的意图。这样,代码就更容易理解,也更容易维护或修改以供他用。

延伸阅读

如果您想深入了解,本节提供了更多关于该主题的资源。

文章

软件

总结

在本教程中,您已经了解了我们应该如何在 Python 中使用注释、文档字符串和类型提示。具体来说,您现在知道:

  • 如何写一个好而有用的注释
  • 使用文档字符串解释函数的约定
  • 如何使用类型提示来解决 Python 鸭子类型在可读性方面的弱点

掌握机器学习 Python!

Python For Machine Learning

更自信地用 Python 编写代码

...从学习实用的 Python 技巧开始

在我的新电子书中探索如何实现
用于机器学习的 Python

它提供自学教程数百个可运行的代码,为您提供包括以下技能:
调试性能分析鸭子类型装饰器部署等等...

向您展示高级 Python 工具箱,用于
您的项目


查看内容

Python 代码中的注释、文档字符串和类型提示的一项回应

  1. Karl Bergerson 2022 年 2 月 24 日下午 6:09 #

    请找一位母语为英语的人士审阅/编辑评论。

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。