- 为什么记录代码如此重要
- 注释与文档代码
- 注释代码基础
- 通过类型提示(python 3.5+)注释代码
- 使用docstrings记录python代码库
- 文档字符串背景
- 文档字符串类型
- 文档字符串格式
- 记录您的python项目
- 私人项目
- 共享项目
- 公共和开源项目
- 文档工具和资源
- 我从哪里开始?
欢迎使用完整的指南来编辑你的python代码。无论你是在记录一个小脚本还是一个大项目,无论你是一个初学者还是经验丰富的Python编程老手,本指南将涵盖你需要知道的一切。
本教程分为四个部分:
- 为什么记录代码如此重要:文档简介及其重要性
- 注释与文档代码:概述注释与文档之间的主要区别,以及使用注释的适当时间和方法
- 使用docstrings记录您的python代码库:深入研究docstring中的类、类方法、函数、模块、包和脚本,以及每个类中应该找到的内容。
- 记录您的python项目:必要的元素以及它们应该为您的python项目包含什么
您可以从头到尾阅读本教程,或者跳到您感兴趣的部分。它被设计成双向工作。
为什么注释代码如此重要
当您编写代码时,您为两个主要的访问群体编写代码:您的用户和开发人员(包括您自己)。两个受众同样重要。如果你和我一样,你可能已经打开了旧的代码库,并且对自己想,“我到底在想什么?“如果您在阅读自己的代码时遇到问题,请想象一下您的用户或其他开发人员在尝试使用或贡献代码时所遇到的情况。
相反,我确信您遇到了这样一种情况:您希望在Python中做一些事情,并找到一个看起来像是可以完成工作的伟大库。然而,当您开始使用这个库时,您会寻找关于如何做一些特定的事情的示例、书面报告甚至官方文档,并且不能立即找到解决方案。
在搜索之后,您会发现文档是缺失的,甚至更糟的是,完全缺失了。这是一种令人沮丧的感觉,它会阻止您使用库,无论代码有多棒或有多高效。
在本指南中,您将学习如何从最小的脚本到最大的python项目正确地记录您的python代码,以帮助防止您的用户对您的项目的使用或贡献感到太沮丧。
注释与文档代码
代码告诉你怎么做;注释告诉你为什么。
简单的代码注释
def hello_world():
# A simple comment preceding a simple print statement
print("Hello World")
根据PEP 8,注释的最大长度应为72个字符。即使您的项目将最大行长度更改为大于建议的80个字符,这也是正确的。如果注释将大于注释字符限制,则可以对注释使用多行:
def hello_long_world():
# A very long statement that just goes on and on and on and on and
# never ends until after it's reached the 80 char limit
print("Hellooooooooooooooooooooooooooooooooooooooooooooooooooooooo World")
注释您的代码有[多种用途,包括](https://en.wikipedia.org/wiki/comment UU(计算机编程)用途):
*规划和审阅:在开发代码的新部分时,可以首先使用注释作为规划或概述该部分代码的一种方式。请记住,在实际编码已经实施并经过评审/测试之后,删除这些注释:
# First step
# Second step
# Third step
代码描述:注释可用于解释代码特定部分的意图:
# Attempt a connection based on previous settings. If unsuccessful,
# prompt user for new settings.
算法描述:当使用算法,特别是复杂的算法时,解释算法如何工作或如何在代码中实现是很有用的。描述为什么选择了一个特定的算法而不是另一个算法也是合适的。
# Using quick sort for performance gains
标记:标记的使用可用于标记已知问题或改进区域所在的特定代码部分。例如:bug、fixme和todo。
# TODO: Add condition for when val is None
对代码的注释应该保持简短和集中。尽可能避免使用长注释。此外,您还应使用Jeff Atwood建议的以下四个基本规则:
1.使注释尽可能接近所描述的代码。不接近描述代码的注释会让读者感到沮丧,并且在进行更新时很容易被忽略。
2.不要使用复杂的格式(如表格或ascii数字)。复杂的格式会导致内容分散注意力,并且随着时间的推移很难维护。
3.不要包含多余的信息。假设代码的读者对编程原理和语言语法有基本的理解。
4.设计代码以注释自身。理解代码的最简单方法是阅读它。当您使用清晰易懂的概念设计代码时,读者将能够快速概念化您的意图。
记住,评论是为读者(包括你自己)设计的,目的是帮助他们理解软件的目的和设计。
通过类型提示注释代码(python 3.5+)
类型提示已添加到Python3.5中,是帮助代码读者的附加表单。事实上,杰夫的第四个建议是从上到下一个层次的。它允许开发人员设计和解释部分代码而无需注释。下面是一个简单的例子:
def hello_name(name: str) -> str:
return(f"Hello {name}")
通过检查类型提示,您可以立即知道函数希望输入名称是str或string类型。您还可以知道函数的预期输出也将是str或string类型。虽然类型提示有助于减少注释,但要考虑到在创建或更新项目文档时,这样做也可能会带来额外的工作。
您可以从dan bader创建的视频中了解有关类型提示和类型检查的更多信息。
使用docstring记录python代码库
既然我们已经了解了注释,那么让我们深入了解一下如何记录python代码库。在本节中,您将学习docstring以及如何将它们用于文档。本节进一步分为以下小节:
1.docstrings背景:关于docstrings如何在python内部工作的背景
2.docstring类型:各种docstring“类型”(函数、类、类方法、模块、包和脚本)
3.docstring格式:不同的docstring“格式”(google、numpy/scipy、structured text和epytext)
文档字符串背景
编写python代码的文档都以docstring为中心。这些是内置字符串,如果配置正确,可以帮助用户和您自己处理项目文档。除了docstring,python还有一个内置的函数help(),它将对象docstring输出到控制台。下面是一个简单的例子:
>>> help(str)
Help on class str in module builtins:
class str(object)
| str(object='') -> str
| str(bytes_or_buffer[, encoding[, errors]]) -> str
|
| Create a new string object from the given object. If encoding or
| errors are specified, then the object must expose a data buffer
| that will be decoded using the given encoding and error handler.
| Otherwise, returns the result of object.__str__() (if defined)
| or repr(object).
| encoding defaults to sys.getdefaultencoding().
| errors defaults to 'strict'.
# Truncated for readability
如何生成此输出?由于python中的所有内容都是一个对象,因此可以使用dir()命令检查对象的目录。我们来看看有什么发现:
>>> dir(str)
['__add__', ..., '__doc__', ..., 'zfill'] # Truncated for readability
在这个目录输出中,有一个有趣的属性,即“doc”。如果您检查该属性,您将发现:
>>> print(str.__doc__)
str(object='') -> str
str(bytes_or_buffer[, encoding[, errors]]) -> str
Create a new string object from the given object. If encoding or
errors are specified, then the object must expose a data buffer
that will be decoded using the given encoding and error handler.
Otherwise, returns the result of object.__str__() (if defined)
or repr(object).
encoding defaults to sys.getdefaultencoding().
errors defaults to 'strict'.
喂!您已经找到docstring在对象中的存储位置。这意味着您可以直接操作该属性。但是,对于内置设备有一些限制:
>>> str.__doc__ = "I'm a little string doc! Short and stout; here is my input and print me for my out"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'str'
可以操纵任何其他自定义对象:
def say_hello(name):
print(f"Hello {name}, is it me you're looking for?")
say_hello.__doc__ = "A simple function that says hello... Richie style"
>>> help(say_hello)
Help on function say_hello in module __main__:
say_hello(name)
A simple function that says hello... Richie style
python还有一个特性可以简化docstring的创建。不是直接操作“文档”属性,而是将字符串文本放置在对象正下方的策略性位置自动设置“文档”值。下面是与上面相同的例子:
def say_hello(name):
"""A simple function that says hello... Richie style"""
print(f"Hello {name}, is it me you're looking for?")
>>> help(say_hello)
Help on function say_hello in module __main__:
say_hello(name)
A simple function that says hello... Richie style
给你!现在您了解了docstring的背景。现在是时候了解不同类型的docstring以及它们应该包含哪些信息了。
文档字符串类型
PEP 257中描述了docstring约定。它们的目的是为用户提供对象的简要概述。它们应该保持足够简洁,易于维护,但仍然要足够详细,以便新用户了解其目的和如何使用文档对象。
在所有情况下,docstrings都应该使用三重双引号(“”)字符串格式。无论docstring是否是多行的,都应该这样做。docstring至少应该是您描述的内容的快速摘要,并且应该包含在一行中:
"""This is a quick summary line used as a description of the object."""
多行docstring用于在摘要之外进一步详细说明对象。所有多行docstring都有以下部分:
- 单行摘要行
- 进行总结的空行
- 对docstring的任何进一步细化
- 另一个空行
"""This is the summary line
This is the further elaboration of the docstring. Within this section,
you can elaborate further on details as appropriate for the situation.
Notice that the summary and the elaboration is separated by a blank new
line.
"""
# Notice the blank line above. Code should continue on this line.
所有docstring的最大字符长度应与注释相同(72个字符)。docstring可以进一步分为三大类:
类docStrings:类和类方法
包和模块文档字符串:包、模块和函数
脚本文档字符串:脚本和函数
类docstrings
类docStrings是为类本身以及任何类方法创建的。docStrings紧跟在类或类方法之后,该类或类方法缩进一个级别:
class SimpleClass:
"""Class docstrings go here."""
def say_hello(self, name: str):
"""Class method docstrings go here."""
print(f'Hello {name}')
类docStrings应包含以下信息:
对其目的和行为的简要概述
任何公开的方法,以及简短的描述
任何类属性(属性)
与子类的接口相关的任何内容,如果该类是子类的话
类构造函数参数应记录在类方法docstring中。应使用各自的docstring记录各个方法。类方法docStrings应包含以下内容:
方法是什么及其用途的简要说明
传递的任何参数(必需的和可选的),包括关键字参数
标记任何被视为可选或具有默认值的参数
执行方法时发生的任何副作用
引发的任何异常
对何时可以调用方法的任何限制
让我们举一个表示动物的数据类的简单例子。此类将包含几个类属性、实例属性、初始化和单个实例方法:
class Animal:
"""
A class used to represent an Animal
...
Attributes
----------
says_str : str
a formatted string to print out what the animal says
name : str
the name of the animal
sound : str
the sound that the animal makes
num_legs : int
the number of legs the animal has (default 4)
Methods
-------
says(sound=None)
Prints the animals name and what sound it makes
"""
says_str = "A {name} says {sound}"
def __init__(self, name, sound, num_legs=4):
"""
Parameters
----------
name : str
The name of the animal
sound : str
The sound the animal makes
num_legs : int, optional
The number of legs the animal (default is 4)
"""
self.name = name
self.sound = sound
self.num_legs = num_legs
def says(self, sound=None):
"""Prints what the animals name is and what sound it makes.
If the argument `sound` isn't passed in, the default Animal
sound is used.
Parameters
----------
sound : str, optional
The sound the animal makes (default is None)
Raises
------
NotImplementedError
If no sound is set for the animal or passed in as a
parameter.
"""
if self.sound is None and sound is None:
raise NotImplementedError("Silent Animals are not supported!")
out_sound = self.sound if sound is None else sound
print(self.says_str.format(name=self.name, sound=out_sound))
包和模块文档字符串
包docstrings应该放在包的初始文件的顶部。此docstring应列出由包导出的模块和子包。
模块docstrings类似于类docstrings。不再记录类和类方法,现在是模块和其中的任何函数。模块docstrings甚至在任何导入之前就放在文件的顶部。模块文档字符串应包括以下内容:
模块及其用途的简要说明
模块导出的任何类、异常、函数和任何其他对象的列表
模块函数的docstring应包含与类方法相同的项:
功能是什么及其用途的简要说明
传递的任何参数(必需的和可选的),包括关键字参数
标记任何被视为可选的参数
执行函数时发生的任何副作用
引发的任何异常
对何时可以调用函数的任何限制
脚本文档字符串
脚本被认为是从控制台运行的单个文件可执行文件。脚本的docstring放在文件的顶部,并且应该有足够的文档记录,以便用户能够充分理解如何使用脚本。当用户错误地传递参数或使用-h选项时,它应该可以用于其“usage”消息。
如果使用argparse,则可以忽略参数特定的文档,前提是argparser.parser.add_argument函数的帮助参数中正确地记录了该文档。建议对argparse.argumentparser的构造函数中的description参数使用'uuu doc'。有关如何使用argparse和其他常用命令行解析器的详细信息,请参阅我们的命令行解析库教程。
最后,任何自定义或第三方导入都应列在docstring中,以便用户知道运行脚本可能需要哪些包。下面是一个脚本示例,用于简单地打印电子表格的列标题:
"""Spreadsheet Column Printer
This script allows the user to print to the console all columns in the
spreadsheet. It is assumed that the first row of the spreadsheet is the
location of the columns.
This tool accepts comma separated value files (.csv) as well as excel
(.xls, .xlsx) files.
This script requires that `pandas` be installed within the Python
environment you are running this script in.
This file can also be imported as a module and contains the following
functions:
* get_spreadsheet_cols - returns the column headers of the file
* main - the main function of the script
"""
import argparse
import pandas as pd
def get_spreadsheet_cols(file_loc, print_cols=False):
"""Gets and prints the spreadsheet's header columns
Parameters
----------
file_loc : str
The file location of the spreadsheet
print_cols : bool, optional
A flag used to print the columns to the console (default is
False)
Returns
-------
list
a list of strings used that are the header columns
"""
file_data = pd.read_excel(file_loc)
col_headers = list(file_data.columns.values)
if print_cols:
print("\n".join(col_headers))
return col_headers
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument(
'input_file',
type=str,
help="The spreadsheet file to pring the columns of"
)
args = parser.parse_args()
get_spreadsheet_cols(args.input_file, print_cols=True)
if __name__ == "__main__":
main()
文档字符串格式
您可能已经注意到,在本教程中给出的所有示例中,都有使用公共元素(参数、返回和属性)的特定格式。有一些特定的docstring格式可用于帮助docstring解析器和用户拥有熟悉和已知的格式。本教程示例中使用的格式是numpy/scipy样式的docstrings。一些最常见的格式如下:
Formatting Type | Description | Supported by Sphynx | Formal Specification |
---|---|---|---|
Google docstrings | Google’s recommended form of documentation | Yes | No |
reStructured Text | Official Python documentation standard; Not beginner friendly but feature rich | Yes | Yes |
NumPy/SciPy docstrings | NumPy’s combination of reStructured and Google Docstrings | Yes | Yes |
Epytext | A Python adaptation of Epydoc; Great for Java developers | Not officially | Yes |
docstring格式的选择取决于您,但是您应该在整个文档/项目中使用相同的格式。下面是每种类型的示例,让您了解每种文档格式的外观。
Google Docstrings Example
"""Gets and prints the spreadsheet's header columns
Args:
file_loc (str): The file location of the spreadsheet
print_cols (bool): A flag used to print the columns to the console
(default is False)
Returns:
list: a list of strings representing the header columns
"""
reStructured Text Example
"""Gets and prints the spreadsheet's header columns
:param file_loc: The file location of the spreadsheet
:type file_loc: str
:param print_cols: A flag used to print the columns to the console
(default is False)
:type print_cols: bool
:returns: a list of strings representing the header columns
:rtype: list
"""
NumPy/SciPy Docstrings Example
"""Gets and prints the spreadsheet's header columns
Parameters
----------
file_loc : str
The file location of the spreadsheet
print_cols : bool, optional
A flag used to print the columns to the console (default is False)
Returns
-------
list
a list of strings representing the header columns
"""
Epytext Example
"""Gets and prints the spreadsheet's header columns
@type file_loc: str
@param file_loc: The file location of the spreadsheet
@type print_cols: bool
@param print_cols: A flag used to print the columns to the console
(default is False)
@rtype: list
@returns: a list of strings representing the header columns
"""
记录python项目
python项目有各种形状、大小和用途。你记录项目的方式应该适合你的具体情况。记住你的项目的用户是谁,并适应他们的需求。根据项目类型,推荐文档的某些方面。项目的总体布局及其文件应如下:
project_root/
│
├── project/ # Project source code
├── docs/
├── README
├── HOW_TO_CONTRIBUTE
├── CODE_OF_CONDUCT
├── examples.py
项目通常可以分为三种主要类型:私有、共享和公共/开源。
私有项目
私有项目是仅供个人使用的项目,通常不会与其他用户或开发人员共享。对于这些类型的项目,文档可能非常简单。根据需要,可以添加一些推荐的部件:
Readme: 项目及其目的的简要概述。包括安装或操作项目的任何特殊要求。
examples.py:一个python脚本文件,提供了如何使用项目的简单示例。
请记住,即使私人项目是为您个人设计的,您也被视为用户。考虑任何可能会让您困惑的事情,并确保在评论、文档字符串或自述文件中捕获这些内容。
共享项目
共享项目是指在项目的开发和/或使用过程中与其他人协作的项目。项目的“客户”或用户仍然是您自己,以及使用项目的少数人。
文档应该比私有项目更严格一点,主要是帮助新成员加入项目或提醒贡献者/用户项目的新更改。建议添加到项目中的部分如下:
Readme:项目及其目的的简要概述。包括安装或操作项目的任何特殊要求。此外,添加自上一版本以来的任何主要更改。
examples.py:一个python脚本文件,提供了如何使用项目的简单示例。
How to Contribute:这应该包括项目的新贡献者如何开始贡献。
公共和开源项目
公共和开放源码项目是打算与大量用户共享的项目,可以涉及大型开发团队。这些项目应该像项目本身的实际开发一样,把项目文档放在高度优先的位置。建议添加到项目中的部分如下:
Readme:项目及其目的的简要概述。包括安装或操作项目的任何特殊要求。此外,添加自上一版本以来的任何主要更改。最后,添加到进一步文档、错误报告和项目的任何其他重要信息的链接。丹·贝德为你的自述文件提供了一个很好的教程。
How to Contribute:这应该包括项目的新贡献者如何提供帮助。这包括开发新的特性、修复已知的问题、添加文档、添加新的测试或报告问题。
Code of Conduct:定义其他贡献者在开发或使用您的软件时应如何对待对方。这也说明了如果这个代码被破坏将会发生什么。如果您使用的是github,那么可以使用推荐的措辞生成行为准则模板。特别是对于开源项目,考虑添加这个。
License:描述项目正在使用的许可证的纯文本文件。特别是对于开源项目,考虑添加这个。
docs:包含更多文档的文件夹。下一节将更全面地描述应该包括哪些内容以及如何组织此文件夹的内容。
文档文件夹的四个主要部分
Daniele Procida发表了一篇精彩的Pycon 2017演讲和随后关于记录Python项目的博客文章。他提到所有的项目都应该有以下四个主要部分来帮助你集中精力工作:
教程:引导读者通过一系列步骤完成项目(或有意义的练习)的课程。面向用户学习。
如何指导:指导读者完成解决常见问题所需的步骤(面向问题的食谱)。
参考文献:阐明和阐明某一特定主题的解释。倾向于理解。
说明:机器的技术说明和操作方法(关键类、功能、api等)。想想百科全书的文章。
下表显示了所有这些部分之间的关系以及它们的总体目的:
Most Useful When We’re Studying | Most Useful When We’re Coding | |
---|---|---|
Practical Step | Tutorials | How-To Guides |
Theoretical Knowledge | Explanation | Reference |
最后,您要确保您的用户能够访问他们可能有的任何问题的答案。通过以这种方式组织项目,您将能够轻松地回答这些问题,并以他们能够快速导航的格式回答这些问题。
文档工具和资源
编写代码文档,特别是大型项目,可能会让人望而生畏。谢天谢地,有一些工具和参考资料可以帮助您开始:
Tool | Description |
---|---|
Sphinx | A collection of tools to auto-generate documentation in multiple formats |
Epydoc | A tool for generating API documentation for Python modules based on their docstrings |
Read The Docs | Automatic building, versioning, and hosting of your docs for you |
Doxygen | A tool for generating documentation that supports Python as well as multiple other languages |
MkDocs | A static site generator to help build project documentation using the Markdown language |
pycco | A “quick and dirty” documentation generator that displays code and documentation side by side. Check out our tutorial on how to use it for more info. |
除了这些工具之外,还有一些附加的教程、视频和文章,在编写项目文档时非常有用:
有时候,学习的最好方法就是模仿别人。以下是一些很好地使用文档的项目的示例:
我从哪里开始?
项目文档有一个简单的过程:
没有文档
一些文件
完整的文件
好的文件
伟大的文献
如果您不知道下一步该如何处理文档,请查看与上面的进度相关的项目现在的位置。你有什么文件吗?如果没有,那就从那里开始。如果您有一些文档,但缺少一些关键项目文件,请从添加这些文件开始。
最后,不要因为编写代码所需的工作量而气馁或不知所措。一旦你开始记录你的代码,继续下去就变得更容易了。如果您有任何问题,请随时发表评论,或者在社交媒体上联系真正的python团队,我们将提供帮助。