説明文の実行例も自動で確かめる
関数を修正したのにdocstringの使用例を直し忘れると、説明どおりに試しても同じ結果にならない。doctestを使うと、docstringに書いた>>>から始まる短い対話例を実行し、その次に書いた期待結果と比較できる。使い方を伝える例を、そのまま簡単な回帰確認として利用できるのが利点である。
doctestは標準ライブラリなので、この例に追加パッケージは不要である。説明の短い例を保守する用途に向き、複雑な準備、大量の境界値、外部依存の差し替えなどはpytestの通常のテストへ分けると読みやすい。文書として伝えたい使い方と、網羅的に検査したい条件を無理に一つのdocstringへ詰め込まない。
戻り値・空行・例外をdocstringに書く
labels.py
def compact_label(text):
"""Normalize whitespace in a short label.
>>> compact_label(" sample A ")
'sample A'
>>> print(compact_label(""))
<BLANKLINE>
>>> compact_label(None)
Traceback (most recent call last):
...
TypeError: text must be str
"""
if not isinstance(text, str):
raise TypeError("text must be str")
return " ".join(text.split())
labels.pyとして保存し、python -m doctest -v labels.pyで実行する。-vを付けると、何を試し、何を期待しているかも表示される。ここでは3つの例が成功した。次は実行結果の末尾部分である。
実行結果(抜粋)
3 passed and 0 failed.
Test passed.
説明だけ古くなった例を実際に失敗させる
broken_doc.py
def twice(value):
"""Double a value.
>>> twice(3)
7
"""
return value * 2
こちらは説明文の期待値7が誤っている。python -m doctest broken_doc.pyを実行すると失敗し、終了コードは1になる。下は実際の失敗表示から、ExpectedとGotの部分を抜粋したもの。関数は6を返しているので、仕様が「2倍」であることを確認して期待値を6へ直す。
実行結果(抜粋)
Expected:
7
Got:
6
表示されるものを正確に書く
対話環境で式を評価した戻り値はrepr()に相当する表記で表示されるため、文字列の例には引用符が付く。一方、print()の結果には通常その引用符が付かない。コードが同じ文字列を扱っていても、何を表示しているかによって期待出力は変わる。例の最初は戻り値、二つ目はprintの表示である。
期待結果中の空行は<BLANKLINE>と書く。単なる空行を置くと例の区切りとして扱われるため、出力された空行を明示する必要がある。複数行のコードは…で継続行を書くが、これは任意の結果を省略するための指定とは別である。対話形式の記号と結果を混ぜないようにする。
例外を期待する場合はTracebackの行と例外の種類・メッセージを書く。途中のスタックのファイル名や行番号は例の本質ではないので、例のように省略できる。ここではNoneを渡したときTypeErrorになることを確認し、正しい入力だけを説明するdocstringより契約が分かりやすくなる。
再現できない出力を持ち込まない
現在時刻、一時ファイルの絶対パス、ランダムな値、集合の表示順、外部サービスの結果などは実行環境で変わる。説明に必要なら値を固定したり、並び順をsorted()で整えたりしてから表示する。実行ごとに変わる値をそのまま期待結果へ貼り付けると、関数に問題がなくても失敗し続ける。
ELLIPSISやNORMALIZE_WHITESPACEなどのオプションで比較を緩めることもできるが、必要な箇所に限る。出力の重要な違いまで無視すると、説明が古くなったことを検知できなくなる。浮動小数点なら表示桁数を決めた例にするなど、読者にも意味の分かる形で安定させるのがよい。
文書の検査もコードの実行である
doctestは書かれた例を実行するので、他者が作った任意の文書を無条件に検査してよいわけではない。ファイルを消す例や通信する例があれば、その副作用も起きうる。自分が管理する例を、限定したデータで実行する。モジュールのimport時に処理が走る場合もあるため、関数の定義と実行入口を分けておく。
成功したlabels.pyの3例と、意図的に失敗するbroken_doc.pyの1例は別々に実行した。全部の例が成功したわけではない。普段の文書検査へ組み込む際は誤った期待値を修正し、コード変更と説明変更を同じ機会に確認する。短い使い方が正しく保たれるだけでも、後から関数を使う人の手戻りを減らせる。
実行環境と関連情報
掲載コードはLinux上のCPython 3.12.14で実行した。OS固有のファイル操作や対話環境の違いは、本文に記した条件に従って扱う。
関連:pytestで正常系と異常系の自動テストを始める / pytestのparametrizeで境界値と入力パターンをまとめて検証する
- Python公式:doctest(2026年10月2日参照)
