# docstring ってなに?
PyCon の動画をお借りいたしました。 PyCon というのは、年に一回開催されている Python 祭りのようなものです。
じゃあなんで、お前は、この記事書いたんだ?って話です。 この記事のそのものは PEP 257 があるってことをなんとなく知ってもらうための記事です。
前回の記事で PEP 7、前々回の記事で PEP 8 について触れてきました。 ここでは PEP 257 に触れて、次の記事で PEP そのものについて触れていきます。 左側のサイドバーに目次がございますので、ご確認いただければと思います。
# 「ドキュメント」ってなに?
Python に限らずモジュール、クラス、関数の動作について書かれた説明を、
よく「ドキュメント」と呼んだりします。
例えばソートされたリストにソートされた状態を保ったまま、
要素を挿入できる bisect.insort_right
という関数があります。
import bisect.insort_right
# ソートされたリストであれば...
lst = [0, 3, 5, 6, 9, 10]
# ソートしたあともソートした状態を保っている...
insort_right(lst, 7)
lst
# [0, 3, 5, 6, 7, 9, 10]
例えば標準ライブラリ bisect (opens new window) の「ドキュメント」を例示してみます。 原文は英語ですが、雰囲気を掴みやすくするために日本語訳しています。
"""二分探索アルゴリズム.""" # <--- モジュールの「ドキュメント」
def insort_right(a, x, lo=0, hi=None):
"""リスト a に値 x を挿入する、
リスト a がソートされているならば
値 x を挿入した後もリスト a はソートした状態を保っている。
値 x と同じ値が既にリスト a にあるならば、
既にある値の一番右側に挿入される。
オプション引数である lo (規定値 0) と hi (規定値 len(a)) は
検索対象となる a のスライスの境界を引く。
""" # <--- 関数の「ドキュメント」
if lo < 0:
raise ValueError('lo must be non-negative')
if hi is None:
hi = len(a)
while lo < hi:
mid = (lo+hi)//2
if x < a[mid]: hi = mid
else: lo = mid+1
a.insert(lo, x)
# 疑問 1. なんで「ドキュメント」を書くの?
答え: 他の人や、あるいは将来の自分に説明するために書きます。
まず、他の方が、書いたコードを読むときは、やっぱりドキュメントが無いと結構辛い思いをします。 また、自分が、書いたコードでさえ、しばらく経てば何を書いていたかわからなくなります。
第 1 位 6 か月後の自分のコード - プログラマを悩ませること Top 10 (opens new window)
自分が作った昔のコードを見て、顔をゆがめたことはありせんか? なんてバカなんだ! この私がなんでこんなコードを書いたのだろう? 燃やして! 火をつけて燃やして! 安心してください。そう思ったことがあるのはあなただけではありません。
# 疑問 2. なんで docstring って名前がついてるの?
答え: Python では「ドキュメント」も文字列, str 型の「オブジェクト」だからです。 Python では「トキュメント」は「コメント」ではありません。
ドキュメント document と文字列 string, この2つ合わせて docstring という訳です。
document + string -> docstring
docstring についてもう少し正確に言うと、 関数定義文やクラス定義文の中で、 最初に書かれる str 型のオブジェクトを指しています。
Docstring ってなに? - PEP 257 (opens new window)
docstring とは、モジュール, 関数, クラス, メソッドの定義の中で、最初に文として登場する文字列リテラルです。 そのような docstring は オブジェクトの特殊属性 special attribute の __doc__ に代入されます。
What is a Docstring? - PEP 257
A docstring is a string literal that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the __doc__ special attribute of that object.
反対にコメントは str 型のオブジェクトではありません。 そのため変数や属性に代入しようとするとエラーになります。
# SyntaxError になります。
c = # Hello, world!
>>> c = # Hello, world!
File "stdin", line 1
c = # Hello, world!
^
SyntaxError: invalid syntax
>>>
docstring は、次のうちどれに分類されますか?
# docstring を活用する。
大抵の他の言語では「ドキュメント」は「コメント」として書かれます。 しかし Python の「ドキュメント」は str 型 のため、 色々と使い回しが効きます。
# 活用例 1. docstring を活用した「組み込み関数」
組み込み関数とは import しなくても使える関数です。 組み込み関数 help を使いサクッと docstring を閲覧できるようになっています。
# インタラクティブシェルに
# コピペして実行してみてください。
def factorial(n):
"""階乗を求める。 <--- これが docstring
Args:
n: int 型, 整数
Returns:
n の階乗
"""
if n == 1:
return 1
else:
return n * factorial(n)
# 1) docstring とは
# 関数定義文やクラス定義文で最初に定義された
# str 型のオブジェクトです。
# 2) この str 型のオブジェクト docstring は
# 特殊属性 special attribute の __doc__ に
# 代入されます。
factorial.__doc__
# 3) help 関数で呼び出すことができます。
# 自分で書いた関数を help で呼び出すようなことはしませんが
# 他の方が書いたコードを help を使って読むことは、よくあります。
help(factorial)
>>>
>>> help(factorial)
---
画面が切り替わります。
---
Help on function factorial in module __main__:
factorial(n)
階乗を求める。
Args:
n: int
Returns:
n の階乗
---
'q' キーを押すと抜けられます。
最初は抜けられなくて焦ります笑
---
>>>
Python ではドキュメントを書く位置についても「コーディング規約」ではなく 機能として、ここに書いてね、と指定しています。
これはコードのブロックを他の言語のように括弧 { }
ではなく、
インデントで分けるように書いたのと考え方が似てるかなと思います。
# 活用例 2. docstring を活用した「標準ライブラリ」
蛇足ですが docstring を活用した「標準ライブラリ」が2つあります。 せっかく「標準ライブラリ」という言葉を覚えたので使ってみたくなっただけです笑
これらは、気が向いたらちらっと覗いてみてください。 僕も名前を知ってるだけで理解もしてませんし、まだ使ったことがありません。
1つ目は pydoc です。pydoc は docstring からオンラインマニュアルを生成してくれます。 Javadoc に影響されたものなのでしょうか。
2つ目は pydoctest です。pydoctest は docstring に書かれた使用例を元に簡易的なテストを実行してくれます。
# PEP 257 ってなに?
PEP 257 (opens new window) では docstring の書き方を定めています。 PEP 8 の docstring 版です。
この文書と PEP 257 (Docstring 規約) は、 Guido が書いたオリジナルのPythonスタイルガイドのエッセイと、 Barry のスタイルガイドに少し追記したものをまとめたものです。
Python コードのスタイルガイド - PEP 8 (opens new window)
PEP 257 そのものの解説は、差し控えさせていただきたいと思います。 ここでは docstring というものの存在だけ知っていただければと思いました。 ちなみに pydocstyle (opens new window) というリンターがあります。
PEP には 標準ライブラリに関するドキュメント規約がある。