在 Sphinx 中描述代码¶
在本教程的前几节中,你可以阅读如何在 Sphinx 中编写叙述性或散文式文档。在本节中,你将描述代码对象。
Sphinx 支持文档化多种语言的代码对象,包括 Python、C、C++、JavaScript 和 reStructuredText。它们都可以使用一系列指令和角色进行文档化,这些指令和角色按域分组。在本教程的剩余部分,你将使用 Python 域,但本节中看到的所有概念也适用于其他域。
Python¶
文档化 Python 对象¶
Sphinx 提供了几个角色和指令来文档化 Python 对象,所有这些都分组在Python 域中。例如,你可以使用 py:function
指令来文档化一个 Python 函数,如下所示
Creating recipes
----------------
To retrieve a list of random ingredients,
you can use the ``lumache.get_random_ingredients()`` function:
.. py:function:: lumache.get_random_ingredients(kind=None)
Return a list of random ingredients as strings.
:param kind: Optional "kind" of ingredients.
:type kind: list[str] or None
:return: The ingredients list.
:rtype: list[str]
这将渲染成这样

在 Sphinx 中文档化 Python 函数的渲染结果¶
注意以下几点
Sphinx 解析了
.. py:function
指令的参数,并适当地高亮显示了模块、函数名和参数。指令内容包括函数的单行描述,以及一个包含函数参数、其预期类型、返回值和返回类型的信息字段列表。
注意
py:
前缀指定了域。你可以配置默认域,以便可以省略前缀,可以全局使用 primary_domain
配置,或者使用 default-domain
指令从调用它的点更改到文件末尾。例如,如果将其设置为 py
(默认值),你可以直接写 .. function::
。
交叉引用 Python 对象¶
默认情况下,这些指令中的大多数会生成实体,这些实体可以使用相应的角色从文档的任何部分进行交叉引用。对于函数的情况,你可以使用 py:func
,如下所示
The ``kind`` parameter should be either ``"meat"``, ``"fish"``,
or ``"veggies"``. Otherwise, :py:func:`lumache.get_random_ingredients`
will raise an exception.
当生成代码文档时,Sphinx 会自动生成交叉引用,只需使用对象的名称即可,而无需显式使用角色。例如,你可以使用 py:exception
指令来描述函数引发的自定义异常
.. py:exception:: lumache.InvalidKindError
Raised if the kind is invalid.
然后,将此异常添加到函数的原始描述中
.. py:function:: lumache.get_random_ingredients(kind=None)
Return a list of random ingredients as strings.
:param kind: Optional "kind" of ingredients.
:type kind: list[str] or None
:raise lumache.InvalidKindError: If the kind is invalid.
:return: The ingredients list.
:rtype: list[str]
最后,结果将如下所示

在 Sphinx 中文档化带有交叉引用的 Python 函数的 HTML 结果¶
很漂亮,不是吗?
在文档中包含 doctest¶
既然你现在正在描述来自 Python 库的代码,那么尽可能保持文档和代码同步将变得很有用。在 Sphinx 中实现这一目标的方法之一是在文档中包含代码片段,称为 *doctest*,它们在构建文档时执行。
为了演示 doctest 和本教程中涵盖的其他 Sphinx 功能,Sphinx 需要能够导入代码。为了实现这一点,请在 conf.py
的开头写入以下内容
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here.
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[2]))
注意
更改 sys.path
变量的替代方法是创建一个 pyproject.toml
文件并使代码可安装,使其行为类似于任何其他 Python 库。但是,sys.path
方法更简单。
然后,在向文档添加 doctest 之前,在 conf.py
中启用 doctest 扩展
extensions = [
'sphinx.ext.duration',
'sphinx.ext.doctest',
]
接下来,按如下方式编写 doctest 代码块
>>> import lumache
>>> lumache.get_random_ingredients()
['shells', 'gorgonzola', 'parsley']
Doctest 包括要运行的 Python 指令,前面是 >>>
,标准的 Python 解释器提示符,以及每个指令的预期输出。这样,Sphinx 可以检查实际输出是否与预期输出匹配。
为了观察 doctest 失败的样子(而不是像上面的代码错误),让我们先错误地编写返回值。因此,添加一个像这样的 get_random_ingredients
函数
def get_random_ingredients(kind=None):
return ["eggs", "bacon", "spam"]
你现在可以运行 make doctest
来执行文档的 doctest。最初这将显示一个错误,因为实际代码的行为与指定的行为不符
(.venv) $ make doctest
Running Sphinx v4.2.0
loading pickled environment... done
...
running tests...
Document: usage
---------------
**********************************************************************
File "usage.rst", line 44, in default
Failed example:
lumache.get_random_ingredients()
Expected:
['shells', 'gorgonzola', 'parsley']
Got:
['eggs', 'bacon', 'spam']
**********************************************************************
...
make: *** [Makefile:20: doctest] Error 1
正如你所看到的,doctest 报告了预期结果和实际结果,以便于检查。现在是时候修复这个函数了
def get_random_ingredients(kind=None):
return ["shells", "gorgonzola", "parsley"]
最后,make doctest
报告成功!
但是,对于大型项目,这种手动方法可能会变得有点乏味。在下一节中,你将看到如何自动化这个过程。
其他语言(C、C++ 等)¶
文档化和交叉引用对象¶
Sphinx 还支持文档化和交叉引用以其他编程语言编写的对象。还有四个额外的内置域:C、C++、JavaScript 和 reStructuredText。第三方扩展可能会为更多语言定义域,例如
例如,要文档化 C++ 类型定义,你将使用内置的 cpp:type
指令,如下所示
.. cpp:type:: std::vector<int> CustomList
A typedef-like declaration of a type.
这将给出以下结果
-
typedef std::vector<int> CustomList¶
类似于 typedef 的类型声明。
所有此类指令然后生成引用,这些引用可以使用相应的角色进行交叉引用。例如,要引用之前的类型定义,你可以使用 cpp:type
角色,如下所示
Cross reference to :cpp:type:`CustomList`.
这将生成一个指向先前定义的超链接:CustomList
。