隨手養成 Python 好習慣-勤註解、善用自動文件產生工具 Sphinx
Last updated on Jan 11, 2021 in Python 模組/套件推薦 , Python 程式設計 - 高階 by Amo Chen ‐ 4 min read
不管是何種程式語言都有註解的需求,而好的程式開發人員都必須具備勤寫註解的美德。
寫註解不僅是為了幫助自己了解程式的相關細節,也是為了能夠讓他人方便於一起參與開發、維護的重要步驟。
正因為現今的系統架構越來越繁雜,而開發人員的大腦記憶能力有限,當他們持續在開發新功能的同時,其實就已經在慢慢淡忘舊功能的實作細節。
特別是每當發現舊功能需要進行維護與除錯時,往往已經過一段時日,開發人員所存的印象早就所剩無幾,更遑論能夠迅速達成維護與除錯的目標。這些現象在程式開發過程屢見不鮮,因此養成撰寫註解的習慣格外重要。
而每個組織對於註解的規定有所不同,但若是對於初學 Python 程式的新進入者而言,可以參考 Google Python Style Guide 對於註解的規範的章節(連結)。
此外,除了註解,通常文件(documentation)也是必備的產出之一,這些細節都可在 GitHub 上的知名專案可見一斑(如 Django , D3 等)。 但基於 DRY(Don’t Repeat Yourself) 原則,我們希望可以在撰寫註解的同時,也一併完成文件的撰寫(相信有許多程式設計師厭惡撰寫文件),因此本文將介紹如何利用 Sphinx 將 Python 中的註解自動萃取出來,並且自動地產生一份文件供人參考。
Sphinx 是一套相當成熟的文件產生工具,除了能夠用來撰寫書籍與網站之外,也能夠用來自動化將程式碼中的註解萃取出來並變成一份文件,目前支援 Python, Javascript, C/C++,同時也有許多開發者貢獻的的套件。
接下來,將分步驟解說如何使用 Sphinx 自動化文件產生工具。
本文環境
在開始本文前,請先確認有 Python 的執行環境,並請安裝以下 Python 套件:
- Sphinx 3.4.3
- Python 3.7
建立專案資料夾結構
首先,我們需要建立一個類似以下的資料夾結構,用來存放我們用 Sphinx 產生的文件資料夾以及我們的 Python 程式碼。
python_project/
├── doc/
└── src/
接下來,我們用以下指令在 doc/
資料夾中建立 Sphinx 專案,過程中 Sphinx 會詢問若干選項,各位可以依照需求進行選擇(本文主要選擇將 build/
與 source/
資料夾分開)。
sphinx-quickstart doc
執行完上述的指令後,我們的資料夾結構會如下所示:
python_project/
├── doc/
│ ├── build
│ └── source
└── src/
其中 doc/source/
裡面存放著我們撰寫的文件與 Sphinx 設定檔,我們會在接下來的步驟中進行教學。
變更 doc/source/conf.py
設定檔
由於我們必須設定讓 Sphinx 可以自動從 src/
資料夾內的 Python 程式內的註解萃取出來,並且做成一份文件,因此我們需要變更 doc/source/conf.p
y 設定檔內的設定。
將 doc/source/conf.py
設定檔以文字編輯器打開後,約莫在一開始的地方,先試著找到以下的註解說明:
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
接著在上述的註解下方加入以下設定,如此一來 Sphinx 就能夠讀取到 src/
資料夾內的 Python 程式檔案:
import os
import sys
sys.path.insert(0, os.path.abspath('../../src/'))
以及,確保 extensions
變數有添加 autodoc
擴充,例如:
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = ['sphinx.ext.autodoc']
如果喜歡 Google 的 Python 註解風格 的話,可以多增加 1 個擴充在 extensions
中:
extensions = ['sphinx.ext.autodoc', 'sphinx.ext.napoleon']
開始於 src/
內撰寫 Python 程式,並且加入 reStructedText 格式的註解
例如本文用以下 Python 程式碼作為示範(Hello.py
):
"""
A simple module for printing "Hello"
.. module:: Hello
.. moduleauthor:: Amo
"""
def print_hello_with_name(name):
"""This function prints hello with a name
Args:
name (str): The name to use.
Returns:
int. The return code::
0 -- this always return 0
Raises:
AttributeError, KeyError
A really simple function. Really!
>>> print_hello_with_name('foo')
Hello, foo
"""
print('Hello', name)
return 0
在上述的程式碼註解中,一開始我們用 .. module:: Hello
說明 module 名稱為 Hello,並且加上 .. moduleauthor:: Amo
標明作者為 Amo, 最後在 print_hello_with_name
函式底下以 docstring 的方式,簡單說明函式的用途等相關資訊。
p.s. 更多的語法可以參考官方文件
編輯 doc/source/index.rst
doc/source/index.rst
是 Sphinx 預設作為首頁(或索引)的檔案,因此我們必須在這個首頁中加入我們需要被引入的文件名稱,以本文為例則是加入一個名為 Hello 的說明文件(注意:Hello 與 .. toctree::
區塊需隔一行):
Contents:
.. toctree::
:maxdepth: 2
Hello
上述代表我們會在首頁中引入 Hello.rst
的內容(Sphinx 預設省略 rst 副檔名),因此我們也必須在 doc/source/
資料夾中新增一個名為 Hello.rst
的檔案。
撰寫 Hello.rst
最後我們必須在 Hello.rst
中指明與哪個存在於 src/
資料夾內的程式有關,例如以下的 Hello.rst
範例,就是利用 .. automodule:: Hello
說明要將 Hello.py
中的註解說明放入文件中,同時指明 Hello module 中有一個稱為 print_hello_with_name
的成員,更多用法同樣可以參考官方文件:
documentation for "Hello"
=========================
.. automodule:: Hello
:noindex:
:members:
:undoc-members:
:show-inheritance:
除了手工撰寫之外,也可以用以下指令讓 Sphinx 掃描 src
資料夾,並自動產生所有的 .rst
檔到 doc/source
資料夾中,接著再進行編輯撰寫文件即可:
$ cd python_project
$ sphinx-apidoc -o doc/source src
p.s. 記得在自動產生的 .rst
檔裡的 .. automodule::
底下加上 :noindex:
代表一切文件內容以 Hello.py
裡的為準
產生文件
當上述 5 個步驟都做完之後,我們就能夠在 doc/
資料夾內輸入以下指令產生文件:
make html
完成之後,doc/build/html/
資料夾內會產生 html 格式的文件,只要利用瀏覽器開啟即可,範例畫面如下圖:
以上, Happy coding !
References
https://www.sphinx-doc.org/en/master/index.html
https://pythonhosted.org/an_example_pypi_project/sphinx.html
https://google.github.io/styleguide/pyguide.html