
C# には C# のコメントの書き方があるように python には python のコメントの書き方がある。
正直、今までは主として利用するのは C# であって、私にとって python は補助的な言語だからと(まとまった学習から)逃げていたのでノウハウが整理されていないし書き方も統一感がない。すこしずつでも python という言語の習慣に従った書き方を勉強していこうと思う。
とりあえず docstring の書き方は前から気になっていたので調べた。
違うことを書いていたらすいません
docstring
一番はじめになるのは python チュートリアルの内容になると思う。
つまりこれ:
def my_function(): """Do nothing, but document it. No, really, it doesn't do anything. """ pass
C# のコメントとは書き方が結構異なっていて、1行目の書き方が独特に見える。なにも考えなければ """ の後はすぐ改行して、次の行からコメントを書いたほうが読みやすいように見えると思う。
これは PEP257 でも示されるように、「最初の行に簡潔な説明を書く」という習慣になっています。習慣なので「守るべき」でしかなくて、守らなかったら~のようなところはあまり考慮するものではないけど、コメントのインテリセンス表示や Sphinx などのツールの妨げになる恐れはあると思います。
では、ドキュメンテーション文字列(docstring)について、内容と書き方に関する慣習を整理しておきます。
- 最初の行(要約)
- 最初の行には、関数やクラスなどの「目的」を短く簡潔に書きます。この行では、対象の「名前」や「型」を書く必要はありません。これらはコードを見れば分かるためです。ただし、対象の名前が動詞で、すでに処理内容を表している場合は例外です。
- 1行目:
- 文のように書く(命令形でなくてもよい)
- 文頭は大文字で始める
- 文末はピリオド(.)で終わる(日本語なら「。」になる)
- 2行目:
- 2行目を空行にすること
- 1行目(要約)と以下の説明部分を視覚的に分ける
- 2行目を空行にすること
- 以降の行(詳細な説明)
- ※コメントスタイルに従う
- 最後行:
- 「"""」だけで終わること
C# の感覚だと、どうしてこのコメントが関数の手前ではなくて関数名のあとに書かれているのか? となる。
/// <summary> /// コメントの例 /// </summary> public void Sample() { // ... }
これは、言語の考え方が関わっていて、python だとこの docstring もデータとして利用可能なものだからです。以下のようにすると、プログラムからも利用、アクセスできる。
print(Sample.__doc__) # python だと「コメントの例」の部分のテキストを取得できる
C# の XML コメントだと実行時には消されてしまうので、実行時にコメントを取得することは困難だと思います。なので、コメント扱いが結構違うことがわかります。
コメントの書き方の注意点は、2行目以降の書き方にあると思います。ここは、自由度が高すぎるため、いくつかの書き方がユーザーに示されています。
- Google style
- NumPy
- reST
reST 形式だと Sphinx を使ってドキュメント生成しやすい一方で、あまり書きやすいコメント形式になっていないのが欠点。(書くのが少し手間でもある)補足すると、ドキュメント生成は Google style でもできてしまうので、ドキュメント生成が得意なフォーマットくらいの位置。
現実的には Google style がよく採用される傾向にあるようです。というのも vscode などのインテリセンスが表示されるとき、最も見た目が最適化されるのは Google style になってしまっている状況みたいです。
なので、整理すると Sphinx での自動ドキュメント化を考えると reST が標準として採用しやすく、Google style のほうが視覚的にわかりやすいので、通常はこっち。
NumPy のスタイルについては言及していないけど、これは数学系のライブラリ。ただ、他のライブラリでも利用されているケースはあるので存在感ゼロというわけでもない。
個人的に NumPy の形式は見やすいと思う。だけど、それはインテリセンスによるコメント表示を利用せずにそのまま生のテキストで見たときの見やすさのようにも思う。なので、記述がすこし手間や余白が多い気がする。他にも、
----------のようなグループを分けるだけの行があったりするので縦長になる傾向にあると思う。
いずれにしても、書き方が整理されているものがいくつかあるので、そのうち最もあなたにとって都合のよいものを選ぼう、という感じになっている。ここでは Google style を調べた。
Google style
サンプル:
def div(x, y): """ Divide two numbers and return the result. This function performs a division and returns the quotient. It raises a ZeroDivisionError if the divisor is zero. Args: x (float): The numerator. y (float): The denominator. Returns: float: The result of division. Raises: ZeroDivisionError: If y is zero. Examples: >>> div(10, 2) 5.0 >>> div(5, 0) Traceback (most recent call last): ... ZeroDivisionError: division by zero """ if y == 0: raise ZeroDivisionError("division by zero") return x / y
用意されているセクションを整理する:
- Attributes(クラスで使用:変数の説明)
- Args(引数の説明)
- Returns(通常関数で使用:戻り値の型+意味)
- Yields(ジェネレータ関数のみ使用:戻り値の型+意味)
- Raises(例外の一覧)
- Examples(使用例:doctest 形式が望ましい)
- Note(補足的な情報)
- Todo(将来的な改善、未対応のメモ)
こんな感じなので、コメントで頻出するセクションは Args, Returns で Raises, Examples が記述の推奨で Note, Todo が記述の任意になると思う。また、クラス、ジェネレータ関数に対してのみ使うセクションもある。使用の際は使い分けに注意する。
Raises を書くときの考え方は色々あると思うけど、基本的には明示的に
raiseしたもの、つまり直接(具体的にコーディングとして)記述した例外を残す必要性は高い。そのほかの例を挙げると、ファイル I/O で open するときのようなケースだとFileNotFoundErrorなど発生が予想できる。この場合だと、記述しておくのは「親切」であって、比較的弱い推奨になる。
Examples の doctest 形式で書いておくとテスト用に別ファイルを作成して test_***.py みたいなので実行するのはライブラリとか、複数ファイルからなる python のプロジェクトだと思う。
単純な1ファイルで完結している python のプログラムだと別ファイルを用意しなくても、テストを実行できるメリットがある。なので、1ファイルでも関数の使い方をコメントに Examples として記述しておくことは望ましい。
doctest の使い方を把握しておくのは docstring を記述するうえで必要な(推奨される)知識になっていると思う。
python -m doctest file.py
(過去に作った関数などの)ユーザー使用を「非推奨」と明示するには?
個人的に気になる欠点として、Google style は非推奨となったメソッドなどを明示する「定型の方法」が提供されていないように思います。(下記は sphinx の例)
C# でも、コメントではなくて属性で Obsolete を付与すると思います。python だと色々な示し方があるようで微妙にどうするのか困る気がする。
組み合わせることもできるのは、覚えておきたい。(例:warnings.warn も出力するし、コメントにも記述する)
- コメントに自分仕様で明示(sphinx などを参考にする)
- warnings.warn()
- decorator
プロパティやメンバ変数
C# の場合は、一律で同じ /// <summary> の書き方ができた。python の場合、関数やメソッド、クラスの説明は上述で対応できるが、プロパティや変数は同じ書き方ができない。
なので、変数に関しては単純なコメントを付与することになる。
class User: """Represents a user.""" name: str # The user's name age: int # The user's age
あるいは:
class User: """Represents a user.""" def __init__(self, name: str, age: int): """ Initialize the user. Args: name (str): The user's name. age (int): The user's age. """ self.name = name # The user's name self.age = age # The user's age

![Python[完全]入門 Python[完全]入門](https://m.media-amazon.com/images/I/41BQqLuD-iL._SL500_.jpg)
![Pythonブートキャンプ[データ分析コース] ~コードを書くチカラを鍛える3週間集中プログラム Pythonブートキャンプ[データ分析コース] ~コードを書くチカラを鍛える3週間集中プログラム](https://m.media-amazon.com/images/I/41FyAoFJxsL._SL500_.jpg)