CUBE SUGAR CONTAINER

技術系のこと書きます。

Python: docstring を書いてみよう

Python の docstring というのは、モジュールやクラス、関数などにつける説明文のこと。 単純なコメントとの違いは、より仕様に近い内容を記述しておくことで API のドキュメントとして利用できる他、別のドキュメントから内容を読み込んで使ったりすることができる。

今回は docstring の書かれたサンプルコードを元に、REPL からその内容を参照したり、ドキュメンテーションツール Sphinx でその内容を読み込むというのを試してみる。

docstring の書かれたソースコードを用意する

以下が docstring の書かれた Python のソースコード。 内容については FizzBuzz 問題を題材にしている。 モジュールや関数の先頭で “”“ や ‘’‘ を使ってコメントを書いておくと、それが自動的に docstring として扱われることになる。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
このモジュールでは FizzBuzz 問題を実装しています。
"""

from __future__ import print_function


def fizzbuzz(n):
    """
    この関数は、与えられた整数が 3 で割り切れるときは 'Fizz' を、
    5 で割り切れるときは 'Buzz' を、その両者で割り切れるときは
    'FizzBuzz' を、いずれでも割り切れないときは数値をそのまま
    文字列に変換して返します。
    """
    if n % 3 == 0 and n % 5 == 0:
        return 'FizzBuzz'

    if n % 3 == 0:
        return 'Fizz'

    if n % 5 == 0:
        return 'Buzz'

    return str(n)


def main():
    """
    モジュールを実行した際のエントリポイントです。
    """
    import sys
    n = int(sys.argv[1])
    ret = fizzbuzz(n)
    print(ret)


if __name__ == '__main__':
    main()

今回の主眼とは異なるものの、動作についても一応は確認しておく。

$ python fizzbuzz.py 1
1
$ python fizzbuzz.py 2
2
$ python fizzbuzz.py 3
Fizz
$ python fizzbuzz.py 4
4
$ python fizzbuzz.py 5
Buzz
$ python fizzbuzz.py 15
FizzBuzz

REPL から docstring の内容を確認する

docstring の最も単純な使い方としては、REPL を使って内容を確認するというものだとおもう。 docstring が書かれているモジュールや関数などに対して組み込み関数 help() を実行することで、内容を読むことができる。

以下のようにして実行するとページャ経由で docstring が読めるので確認してもらいたい。

$ python -q
>>> import fizzbuzz
>>> help(fizzbuzz)
>>> help(fizzbuzz.fizzbuzz)

ちなみに docstring の内容は、それが書かれたオブジェクトの特殊属性の中に記録されている。 Python 自体がそれを管理するという面から言っても、単なるコメントとは異なることがわかる。

>>> fizzbuzz.__doc__
'\nこのモジュールでは FizzBuzz 問題を実装しています。\n'
>>> fizzbuzz.fizzbuzz.__doc__
"\n    この関数は、与えられた整数が 3 で割り切れるときは 'Fizz' を、\n    5 で割り切れるときは 'Buzz' を、その両者で割り切れるときは\n    'FizzBuzz' を、いずれでも割り切れないときは数値をそのまま\n    文字列に変換して返します。\n    :param int n: FizzBuzz にかける値\n    :rtype: str\n    :return: FizzBuzz の結果\n    "

Sphinx のドキュメントから docstring を読み込む

次に応用編として、Sphinx を使って書かれたドキュメントから docstring の内容を読み込んでみることにしよう。 補足しておくと Sphinx というは Python で書かれたドキュメンテーションツールのこと。 Sphinx では、autodoc という拡張を使うことで docstring の内容を読み込むことができる。

Sphinx をインストールする

まずは Sphinx を PyPI からインストールする。

$ pip install sphinx

初期設定を行う

次に sphinx-quickstart コマンドを使って必要なファイルと設定を用意する。 プロジェクト名、著者、バージョン番号を入力して、autodoc 拡張の組み込みに yes と答える以外はエンターを連打して構わない。

$ sphinx-quickstart
Welcome to the Sphinx 1.3.1 quickstart utility.

Please enter values for the following settings (just press Enter to
accept a default value, if one is given in brackets).

Enter the root path for documentation.
> Root path for the documentation [.]:

You have two options for placing the build directory for Sphinx output.
Either, you use a directory "_build" within the root path, or you separate
"source" and "build" directories within the root path.
> Separate source and build directories (y/n) [n]:

Inside the root directory, two more directories will be created; "_templates"
for custom HTML templates and "_static" for custom stylesheets and other static
files. You can enter another prefix (such as ".") to replace the underscore.
> Name prefix for templates and static dir [_]:

The project name will occur in several places in the built documentation.
> Project name: fizzbuzz-doc
> Author name(s): momijiame

Sphinx has the notion of a "version" and a "release" for the
software. Each version can have multiple releases. For example, for
Python the version is something like 2.5 or 3.0, while the release is
something like 2.5.1 or 3.0a1.  If you don't need this dual structure,
just set both to the same value.
> Project version: 0.0.1
> Project release [0.0.1]:

If the documents are to be written in a language other than English,
you can select a language here by its language code. Sphinx will then
translate text that it generates into that language.

For a list of supported codes, see
http://sphinx-doc.org/config.html#confval-language.
> Project language [en]: ja

The file name suffix for source files. Commonly, this is either ".txt"
or ".rst".  Only files with this suffix are considered documents.
> Source file suffix [.rst]:

One document is special in that it is considered the top node of the
"contents tree", that is, it is the root of the hierarchical structure
of the documents. Normally, this is "index", but if your "index"
document is a custom template, you can also set this to another filename.
> Name of your master document (without suffix) [index]:

Sphinx can also add configuration for epub output:
> Do you want to use the epub builder (y/n) [n]:

Please indicate if you want to use one of the following Sphinx extensions:
> autodoc: automatically insert docstrings from modules (y/n) [n]: y
> doctest: automatically test code snippets in doctest blocks (y/n) [n]:
> intersphinx: link between Sphinx documentation of different projects (y/n) [n]:
> todo: write "todo" entries that can be shown or hidden on build (y/n) [n]:
> coverage: checks for documentation coverage (y/n) [n]:
> pngmath: include math, rendered as PNG images (y/n) [n]:
> mathjax: include math, rendered in the browser by MathJax (y/n) [n]:
> ifconfig: conditional inclusion of content based on config values (y/n) [n]:
> viewcode: include links to the source code of documented Python objects (y/n) [n]:

A Makefile and a Windows command file can be generated for you so that you
only have to run e.g. `make html' instead of invoking sphinx-build
directly.
> Create Makefile? (y/n) [y]:
> Create Windows command file? (y/n) [y]: n

Creating file ./conf.py.
Creating file ./index.rst.
Creating file ./Makefile.

Finished: An initial directory structure has been created.

You should now populate your master file ./index.rst and create other documentation
source files. Use the Makefile to build the docs, like so:
   make builder
where "builder" is one of the supported builders, e.g. html, latex or linkcheck.

これで必要なもの一式が作られた。

Makefile    __pycache__ _build      _static     _templates  conf.py     fizzbuzz.py index.rst

試しに初期状態で HTML 形式のドキュメントをビルドしてみよう。

$ make singlehtml

デフォルトでは結果が _build ディレクトリ以下に格納されるので、それを開く。

$ open _build/singlehtml/index.html

初期状態だとこんな感じになった。

f:id:momijiame:20151015210751p:plain

docstring の内容を読み込む

docstring を Sphinx のドキュメントから読むには設定が必要になる。

まず、sphinx-quickstart コマンドで autodoc 拡張を使うかの確認に yes と答えてさえいれば、設定ファイルの中で autodoc 拡張が有効になっているはず。

$ grep -A 2 ^extensions conf.py
extensions = [
    'sphinx.ext.autodoc',
]

次に、Sphinx が Python のモジュールを見つけ出す必要があるので、パスに (fizzbuzz.py のある) 現在のディレクトリを追加しておく。 実際には現在のディレクトリをパスに追加する処理がコメントアウトされた状態で存在するので、そのコメントを外すだけ。

$ sed -i -e "s:^#\(sys.path\):\1:" conf.py
$ grep ^sys.path conf.py
sys.path.insert(0, os.path.abspath('.'))

最後に、実際のドキュメントの書かれた index.rst の中で automodule ディレクティブを使って fizzbuzz モジュールを読み込むように指定する。

$ cat << EOF > index.rst
Welcome to fizzbuzz-doc's documentation!
========================================

.. automodule:: fizzbuzz
   :members:

EOF

再度 HTML 形式でドキュメントをビルドし直そう。 ビルドの中で特にエラーが表示されなければ上手くいっている。

$ make singlehtml
$ open _build/singlehtml/index.html

完成したドキュメントはこのようになった。

f:id:momijiame:20151015212137p:plain

これで作成したモジュールのドキュメントをソースコードから生成することが可能になった。 docstring を書いておけば、いざ API のドキュメンテーションが必要になった場合でも、ソースコードの内容をひたすらコピペするような作業は必要なさそうだ。