3か月前に自分で書いた関数を開いて、何をする関数なのか思い出せなかった経験はありませんか。変数名から推測しながら、結局は中身を1行ずつ読み直すことになります。
私は10年ほどエンジニアとして開発に関わってきましたが、いちばん時間を溶かしたのは他人のコードではなく、説明のない自分のコードでした。
Pythonには、その説明をコードの中に残しておく仕組みが最初から用意されています。docstring(ドックストリング)と呼ばれるものです。
docstringとは、コードの中に置く説明文¶
docstringは、関数やクラス、モジュールの先頭に置く文字列のことです。三重のダブルクォートで囲んで書きます。
まずは、いちばん短い例を見てみましょう。
def tax_included(price):
"""税抜き価格から税込み価格を求める。"""
return int(price * 1.1)
returnの上にある1行が、この関数のdocstringです。ただ文字列が置いてあるだけに見えますが、Pythonはこれを特別に扱います。
どこが特別なのかというと、その文字列が関数の__doc__という属性へ自動的に保存される点です。
print(tax_included.__doc__)
# 税抜き価格から税込み価格を求める。
つまりdocstringは、実行中のプログラムからも読み出せる説明文なのです。ここが、ふだん使っているコメントとの決定的な違いになります。
コメントとdocstringは役割が違う¶
#で書くコメントも説明ですが、Pythonは実行時にそれを完全に捨ててしまいます。プログラムの側からは一切見えません。
両者の違いを表で整理しておきます。
| 項目 | コメント(#) | docstring |
|---|---|---|
| 書く場所 | どこでも | 関数・クラス・モジュールの先頭 |
| 実行時に残るか | 残らない | __doc__に残る |
| help()で読めるか | 読めない | 読める |
| 主な読み手 | コードを直す人 | この関数を使う人 |
| 向いている内容 | なぜこう書いたのか | 何をするものなのか |
使い分けのこつは、読み手を思い浮かべることです。中身を直す人に向けた補足はコメント、外から呼ぶ人に向けた説明はdocstringと考えるとすっきりします。
たとえば、なぜこんな回りくどい計算式なのかという事情はコメント向きです。一方、この関数に何を渡せば何が返るのかという話はdocstring向きになります。
書き方の基本はPEP 257にまとまっている¶
では、どう書けばよいのでしょうか。Pythonには、docstringの書き方の慣習をまとめた文書があります。
PEP 257という番号の提案書です。細かい規則もたくさん載っていますが、はじめのうちに覚えるべき点は2つに絞れます。
1行で済むなら開きクォートと同じ行に書く¶
内容が明らかな関数なら、無理に長く書く必要はありません。1行で言い切ってしまいましょう。
def is_weekend(date):
"""土日ならTrueを返す。"""
return date.weekday() >= 5
このとき、閉じるクォートも同じ行に置きます。前後に空行は入れません。
文末は句点で終える形にすると読みやすくなります。何をするのかを言い切る書き方で揃えておくと、一覧にしたときに見た目が整います。
複数行なら要約・空行・詳細の順¶
説明したいことが増えたら、複数行の形に切り替えます。並べ方には決まった順番があります。
最初の1行に要約を書き、次に空行をひとつ挟み、そのあとへ詳しい説明を続けます。
def load_users(path, encoding="utf-8"):
"""CSVファイルからユーザー一覧を読み込む。
1行目をヘッダーとして扱い、2行目以降を辞書のリストへ変換する。
ファイルが見つからない場合はFileNotFoundErrorを送出する。
"""
...
最初の1行を独立させるのには理由があります。一覧表示や検索結果では、その1行だけが抜き出されて使われるからです。
要約が長いと、肝心なところが途中で切れてしまいます。1行に収まる長さを意識してみてください。
関数だけでなくクラスやモジュールにも書ける¶
docstringを置ける場所は関数だけではありません。クラスの定義直後や、ファイルのいちばん先頭にも同じように書けます。
ファイルの先頭に書いたものは、そのファイル全体の説明として扱われます。
"""社内の勤怠データを集計するためのユーティリティ。
CSVの読み込みと、月ごとの合計時間の算出をまとめている。
"""
class TimeSheet:
"""1人分の勤怠表を表す。"""
私はファイル先頭のdocstringを、いちばん費用対効果が高いと感じています。ファイルを開いた瞬間に、ここが何の置き場なのかがわかるからです。
迷ったら、まずファイルの先頭に3行だけ書く。これだけでも、あとから探す人の負担がぐっと減ります。
help()が読んでいたのはdocstringだった¶
ここで、見覚えのある機能とつながります。対話モードでhelp()を使ったことはありませんか。
help()が画面へ出しているのは、まさにその関数の__doc__の中身です。標準ライブラリの親切な説明も、正体はライブラリ作者が書いたdocstringにほかなりません。
自分で書いた関数でも、同じことが起こります。
help(tax_included)
# Help on function tax_included in module __main__:
#
# tax_included(price)
# 税抜き価格から税込み価格を求める。
docstringを書くと、自分のコードが標準ライブラリと同じやり方で調べられる状態になります。説明を書く行為が、そのまま調べられる仕組みを作っているわけです。
help()そのものの使い方に不安がある方は、こちらもあわせてどうぞ。【関連記事】Pythonのhelp関数とは?公式ドキュメントが苦手な初心者のための調べ方
なお、字下げをそろえた形で取り出したいときはinspect.getdoc()が便利です。先頭の余分な空白をきれいに落として返してくれます。
引数と戻り値の書き方には流派がある¶
関数の説明でいちばん欲しくなるのは、引数と戻り値の情報でしょう。ところがこの部分の書式は、PEP 257では決められていません。
広く使われている書き方が3つあります。特徴を見比べてみましょう。
| 書き方 | 特徴 | よく見かける場所 |
|---|---|---|
| Googleスタイル | 横に短くまとまり、読みやすい | 一般的なアプリ開発 |
| NumPyスタイル | 縦に長いが、説明を厚く書ける | 科学計算やデータ分析 |
| reStructuredText | 文書生成ツールに素直な記法 | 歴史の長いライブラリ |
はじめて選ぶならGoogleスタイルをおすすめします。見出しと内容が素直に並ぶので、書くときに迷いません。
実際に書くと、次のような見た目になります。
def tax_included(price, rate=0.1):
"""税込み価格を返す。
Args:
price: 税抜きの価格。
rate: 消費税率。既定は0.1。
Returns:
小数を切り捨てた税込み価格。
Raises:
ValueError: priceが負の数のとき。
"""
if price < 0:
raise ValueError("priceは0以上にしてください")
return int(price * (1 + rate))
どの流派を選んでも、Sphinxという文書生成ツールのnapoleon拡張が読み取ってくれます。大事なのは、ひとつのプロジェクトの中で書き方を統一することです。
ちなみに引数の型は、docstringへ書くより型ヒントで示すほうが今どきのやり方です。両方に書くと、片方だけ直して食い違う事故が起こります。【関連記事】Pythonの型ヒントとは?型ヒントの基礎を解説
docstringはテストにもなる¶
docstringには、もうひとつ面白い使い道があります。書いた使用例を、そのままテストとして実行できるのです。
対話モードの表示をまねて、>>>で始まる行と、期待する出力を並べて書きます。
def add(a, b):
"""2つの数を足した結果を返す。
>>> add(1, 2)
3
>>> add(-1, 1)
0
"""
return a + b
このファイルをsample.pyとして保存し、標準ライブラリのdoctestへ渡してみます。私の手元のPython 3.11で実行した結果を載せます。
$ python -m doctest sample.py -v
2 tests in 2 items.
2 passed and 0 failed.
Test passed.
期待した出力と実際の結果が食い違うと、ExpectedとGotという形で差分を教えてくれます。説明文がそのまま動作確認になる、ちょっと不思議な仕組みです。
ただし本格的なテストには向きません。分岐や異常系まで詰め込むと読みにくくなるので、そこはテスト専用の道具に任せましょう。【関連記事】pytest入門|Pythonでテストを書く基本を初心者向けに解説
実務で痛い目を見た話¶
ここからは、現場で私が失敗した話をします。docstringの内容が、実装と合わなくなる問題です。
引数をひとつ増やしたのに説明は昔のまま、という状態は驚くほど簡単に起こります。読んだ人が説明を信じて呼び出し、動かずに混乱するわけです。
間違った説明は、説明がないより厄介でした。直す気がないなら、最初から書きすぎないほうが安全という考え方にも一理あります。
そこで私は今、関数名と引数名で伝わることは書かない方針にしています。名前で伝わらないことだけをdocstringへ残す、という線引きです。
もうひとつ、知っておくと役に立つ仕様があります。Pythonを-OOという指定で起動すると、docstringは捨てられます。
そのため、プログラムの動作そのものをdocstringに頼らせてはいけません。あくまで人が読むためのものと考えてください。
読みやすいコードの考え方そのものに興味が湧いた方は、こちらもどうぞ。【関連記事】綺麗なコードって何?初心者から一歩抜け出す「リーダブルコード」の3つの基本
どこから書き始めればいいのか¶
すべての関数に書くぞと意気込むと、たいてい続きません。優先順位をつけるほうが現実的です。
私がすすめているのは、他の人が呼ぶ関数から手をつける順番です。
目安を表にまとめました。
| 優先度 | 対象 | 理由 |
|---|---|---|
| 高 | 外へ公開する関数・クラス | 使う人が中身を読まずに済む |
| 中 | 引数が多い関数 | 名前だけでは意図が伝わらない |
| 中 | 例外を送出する関数 | 呼ぶ側が備えられる |
| 低 | 数行の内部関数 | 名前で十分わかることが多い |
最初は1行のdocstringで構いません。要約だけでも、3か月後の自分がずいぶん助かります。
慣れてきたら、Ruffのようなツールでdocstringの有無を自動チェックする方法もあります。まずは手で書く習慣から始めてみてください。
docstringは、未来の読み手へ宛てた短い手紙のようなものです。きょう書いたいちばん新しい関数に、1行だけ添えてみてはいかがでしょうか。ここまでお読みいただきありがとうございました。