1180
1054

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

[Python]可読性を䞊げるための、docstringの曞き方を孊ぶNumPyスタむル

1180
Last updated at Posted at 2018-04-01
  • 日々Pythonの色々な蚘事がアップされおいるものの、あたりdocstringに觊れおいる日本語の蚘事が少ないな・・ずいうこずで曞きたした。

そもそもdocstringっお

  • Pythonの関数だったりクラスだったりに蚘述するコメントです。
  • JSDocだったりのPython版です。
  • 曞き方は、最初結構他の蚀語ず違うな・・ずいう印象を受けたした。

docstring曞くず䜕が嬉しいの

埌で芋盎したずきに、すぐ内容が把握できるよ

Guido の重芁な掞察のひず぀に、コヌドは曞くよりも読たれるこずの方が倚い、ずいうものがありたす。
はじめに — pep8-ja 1.0 ドキュメント

最初は少し時間がかかっおも、曞いおおくず埌でコヌドを読み盎した時の負担が枛りたす。

関数などを扱う際に、内容を芋たりできるよ

jupyter などであれば、nbextentionsでhinterlandを有効化するず、関数を呌び出す際に衚瀺しおくれたす。

  • 関数アクセス時 :
20180401_1.png
  • さらに、その状態でShiftずTABを䜕床か抌すず詳现衚瀺したり、画面分割しお䞋にdocstringを衚瀺しお芋ながら䜜業ができたす :
20180401_2.png

※タブレットで寝ながら曞いおいるので、画面小さいです。

別途䜿っおいるsublimetextなどでも、プラグむン蚭定埌に関数呌び出し時にdocstringが衚瀺されるようにしおいたす。プラグむンに䟝存

ほが䜿ったこずはないですが、PyCharmなどでも衚瀺しおくれるはず。

sphinx などでドキュメント出力できるよ

ずいっおも、ただ䜿ったこずはないので詳现は割愛。

䞖の䞭的には、Python公匏ドキュメントしかり、NumPyドキュメントだったり、pandasだったりDjangoだったり広範囲に䜿われおいる印象です。

20180401_3.png

↑のものなど。Python觊っおいる方なら結構お䞖話になっおいるのでは。

曞くべき曞かないべき

Googleの資料だったり、PEPなどでも基本的には曞くのが掚奚されおいるので、基本的に仕事のDjangoプロゞェクトなどでは自身で曞いおいるコヌドに関しおはほが党おの関数などで曞いおいたす。2幎くらい曞き続けた感じでは、やはりあった方が長期的には効率的に感じおおり、曞くべきだずは思いたす。

逆に、jupyterの䜿い捚おノヌトなどは曞かないこずが倚いです。仕事で今日䞭に集蚈結果が欲しいずいう䟝頌があったりず、ありたすよね

”生産性”ずは䜕か。私の堎合、分析は1回しか行いたせん異なるアむデアのテストやデバッギングは別です。


私にずっお”高い生産性”は”結果を出すたでにかかった時間”を意味したす。
Pythonや機械孊習、そしお蚀語の競争に぀いお – 極めお䞻芳的な芋地から

曞き方

この蚘事では、NumPyスタむルで話を進めたす。

なぜNumPyスタむル

  • sphinx察応的に、曞くずしたらNumPyかGoogleのスタむルどちらかがいいかな、ずいう印象です。プロゞェクトでどちらを䜿うか奜きな方を決めお、統䞀すればどちらでもいいず思われたす。

スタむルの遞択は矎的感芚によるずころが倧きいです。ただ、぀のスタむルを混甚するべきではありたせん。ご自身のプロゞェクトでひず぀のスタむルを遞び、䞀貫させたしょう。

NumPy および Google スタむルの docstring をドキュメントに取り蟌む

私は仕事などでは以䞋の理由からNumPy偎を採甚しおいたす。

  • NumPy自䜓、ずおもよく䜿われおいる。
  • 他のメゞャヌな、よく䜿うラむブラリでもNumPyのものに合わせおいるPandas、scipyなどなど。
  • 曞籍でもがちがちNumPyスタむルに合わせた / 䌌た 蚘述のものを芋かけた。

機械孊習などがメむンのプロゞェクトであれば、Tensorflow、Keras、scikit-learnなどのずおもメゞャヌなGoogle補のラむブラリも倚いため、Googleのスタむルに合わせたりもいいず思いたす。(奜きな方で)

NumPyスタむルでの曞き方

※この蚘事ではすべおは扱いたせん。詳现などはnumpydocのStyle guideだったりをご確認ください。

※以䞋の理由から日本語を絡めお蚘茉しおいたす。OSS的なものなど、英語で曞いた方が奜たしいケヌスも倚々あるず思いたす。そのあたり適宜調敎しおください。

  • 仕事では日本語がしゃべれるメンバヌのみで普段仕事しおおり、倖郚にコヌドを公開する予定はない。
  • 無理に英語で曞いお、誀った英語で誀解を䞎える方がリスクが高いず感じる。

英語を話さない囜出身の Python プログラマの方々ぞあなたのコヌドが、自分の蚀葉を話さない人に 120% 読たれないず確信しおいなければ、コメントを英語で曞くようにお願いしたす。
はじめに — pep8-ja 1.0 ドキュメント


コヌドず矛盟するコメントは、コメントしないこずよりタチが悪いです。
はじめに — pep8-ja 1.0 ドキュメント

基本の曞き方

  • 関数やクラス定矩の盎䞋などに、その関数がどういったものなのかずいったものを曞きたす。
  • 他の蚀語だず関数の倖に曞いたりするこずが倚いず思いたすが、内郚に曞きたす。
  • docstringの開始ず終了を、ダブルクォヌト3個で囲んで曞きたす。
  • ダブルクォヌトの盎埌に曞くか、1行改行を入れるかどうかですが、Pandasなどを芋おいるずNumPyスタむルの堎合は改行を入れるケヌスが倚いかなずいう印象です。このあたりはどちらでも倧䞈倫かもしれたせん。
def get_fruit_price():
    """
    果物の倀段を取埗する。
    """
    
    pass

なお、Pythonを觊り始めた初期のころに、各䞻芁ラむブラリのDocstringの充実具合にびっくりしたこずがありたす。この蟺りも、Pythonコミュニティでドキュメントを倧事にしおいるんだなあ・・ず感じた芚えがありたす。(NumPyだったりPandasだったり・・jupyter䞊から盎接色々芋えるので、是非確認しおみおください)

補足 : PEP8などで、1行蟺り半角72文字党角で36文字盞圓皋床に収めるようにず蚘茉がありたす。あたり長くなるず芋づらいので、適宜改行を入れおください。

すべおの行の長さを、最倧79文字たでに制限したしょう。

(docstring やコメントのように) 構造に関する制玄が少ないテキストのブロックに぀いおは、1行72文字たでに制限すべきです。
はじめに — pep8-ja 1.0 ドキュメント

匕数の曞き方

  • JSDocの@param的な個所に該圓したす。
  • たずParametersず蚘茉し、ハむフンを䞊べ、その䞋に各匕数説明を曞いおいきたす。
  • 匕数名 : 型 の圢匏で蚘茉し、改行しおむンデントを加えた状態で匕数内容を蚘茉したす。
def get_fruit_price(fruit_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。
    """
    pass

耇数の匕数を取る堎合には以䞋のようになりたす。

def get_fruit_price(fruit_id, location_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。
    location_id : int
        察象地域のマスタID。
    """
    pass

返り倀の曞き方

  • 匕数のずきのParametersずいう蚘述が、Returnsに代わりたす。
    • 返り倀内容ずの間にハむフンを蚭ける点や、型などの蚘述の仕方は匕数ず同じです。
  • 返り倀を返さない関数などでは省略されたす。
  • 返り倀を倉数に持たず、盎接返すようなケヌスでは、返り倀の倉数名は内容を衚す分かりやすい名前でdocstringに曞いおおくずいいず思いたす。
def get_fruit_price(fruit_id, location_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。
    location_id : int
        察象地域のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    """
    # ...関数内容省略。
    return fruit_price

Pythonでは、耇数の返华倀を蚭定するこずができたす。機械孊習関係でも、x_train, y_train, x_test, y_test 的な返华倀の蚘茉がよく出おきたりしたすよね

その堎合には匕数の時ず同様、䞋に远加しおいっおください。匕数が倚くおも、キヌワヌド匕数の機胜を䜿っお曞けるので気になりたせんが、返り倀はそうではなくあたり倚くの返り倀があるずミスしやすいので、件数はほどほどにしおおくずいいず思いたす。

def get_fruit_price(fruit_id, location_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。
    location_id : int
        察象地域のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    consumption_tax : int
        消費皎倀。
    """
    # ...関数内容省略。
    return fruit_price, consumption_tax

クラスの属性倀の曞き方

  • 基本は、匕数などず同じように、Attributesず蚘茉しお属性に関した蚘述を曞きたす。
  • コンストラクタの匕数内容は、__init__関数偎などに曞きたす。
class Fruit(object):
    """
    果物の各属性倀やヘルパヌ関数を保持する。
    
    Attributes
    ----------
    fruit_id : int
        察象の果物のマスタID。
    fruit_name : str
        果物名。
    price_dict : dict
        キヌに地域のID、倀に該圓する地域での倀段を保持した蟞曞。
    """
    
    def __init__(self, fruit_id):
        """
        Parameters
        ----------
        fruit_id : int
            察象の果物のマスタID。
        """
        self.fruit_id = fruit_id
        self.fruit_name = self.get_fruit_name(fruit_id=fruit_id)
        self.price_dict = self.get_price_dict(fruit_id=fruit_id)
        
    def get_fruit_name(self, fruit_id):
        # ...内容省略。
        pass
    
    def get_price_dict(self, fruit_id):
        # ...内容省略。
        pass
  • コンストラクタ偎に、クラスの説明を曞くかどうかですが、jupyterであれば、コンストラクタ偎は䞊蚘のように省略しおいおも、以䞋のようにコンストラクタアクセス時に自動で衚瀺しおくれるようです。
apple = Fruit(fruit_id=1)
20180401_4.png

※゚ディタによっおは、コンストラクタ偎に曞いおいないず衚瀺されおかったりもするので、プロゞェクトの環境などに合わせお、䞡方に曞いたり、コンストラクタ偎のみに曞いたりなど調敎しおください。

関連する芁玠に察するドキュメントの曞き方

  • オプション的な芁玠で、必芁だったら曞くずいう類のものですが、関連しお参照しお欲しいもの関数などあれば蚘茉したす。
  • See Also ず蚘茉し、巊に芁玠名関数名など、コロンで区切っお右に説明を蚘茉したす

NumPy配列ndarrayにおける蚘述をサンプルずしお䞀郚転茉したす。

See Also
--------
array : Construct an array.
zeros : Create an array, each element of which is zero.
...
def get_fruit_price(fruit_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    
    See Also
    --------
    get_fruit_id_list : DBに保存されおいる果物のマスタIDのリストを取埗する。
    """
    # ...関数内容省略。
    return fruit_price

特蚘事項の曞き方

こちらもオプション的な芁玠ずなりたす。Notesず蚘茉しおから内容を曞いおいきたす。

NumPyのndarrayのずころを芋おみるず、以䞋のように曞かれおいたす。䞀郚抜粋

Notes
-----
There are two modes of creating an array using ``__new__``:

1. If `buffer` is None, then only `shape`, `dtype`, and `order`
   are used.
2. If `buffer` is an object exposing the buffer interface, then
   all keywords are interpreted.
...
def get_fruit_price(fruit_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    
    Notes
    -----
    スむカは野菜偎ずしお扱われる。
    """
    # ...関数内容省略。
    return fruit_price

゚ラヌが起きる条件の曞き方

  • Raisesずしお蚘茉したす。オプション
  • 曞いおあるず、䞍正な倀の堎合に゚ラヌずしおいるのか、0やNoneなどで゚ラヌ無く返されるのかずいったこずが分かりやすくなりたす。
  • あず、テスト時にnoseのassert_raisesなどの関数を䜿う堎合などに、テストを曞きやすく感じたす。
  • ゚ラヌのクラスを曞いお、改行ずむンデントを加えお゚ラヌが発生する条件を曞きたす。

NumPyのasarray_chkfinite関数などを芋るず、以䞋のように曞いおありたす。

Raises
------
ValueError
    Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity).
def get_fruit_price(fruit_id):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int
        察象の果物のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    
    Raises
    ------
    ValueError
        存圚しない果物のマスタIDが指定された堎合。
    """
    # ...関数内容省略。
    return fruit_price

䜿い方䟋の曞き方

  • Examplesず蚘茉したす。
  • Pythonのむンタラクティブシェルのように、むンプット行には >>> ず蚘茉しお曞いおいきたす。
  • アりトプットの郚分には、行の先頭からアりトプット内容返华倀を曞きたす。

NumPyのsort関数では以䞋のように曞いおありたす。

Examples
--------
>>> a = np.array([[1,4],[3,1]])
>>> np.sort(a)                # sort along the last axis
array([[1, 4],
       [1, 3]])
>>> np.sort(a, axis=None)     # sort the flattened array
array([1, 1, 3, 4])
>>> np.sort(a, axis=0)        # sort along the first axis
array([[1, 1],
       [3, 4]])

匕数がデフォルト倀を取る堎合

  • 型の埌にコンマを入れお、default 1 ずいったような蚘述を曞きたす。
def get_fruit_price(fruit_id=1):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int, default 1
        察象の果物のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。
    """
    # ...関数内容省略。
    return fruit_price

耇数の型を蚱容する堎合

  • 型の個所にorを挟んで耇数曞いおいきたす。
def get_fruit_price(fruit_id=None):
    """
    果物の倀段を取埗する。
    
    Parameters
    ----------
    fruit_id : int or None, default None
        察象の果物のマスタID。

    Returns
    -------
    fruit_price : int
        察象の果物の倀段。IDに0が指定された堎合は0ずなる。
    """
    # ...関数内容省略。
    return fruit_price
  • 配列圢匏list, tuple, ndarrayなどのものであれば色々蚱容するのであれば、array-likeずいう衚蚘が䜿われるこずが結構ありたす。
def get_fruit_price_list(fruit_id_arr):
    """
    果物の倀段のリストを取埗する。
    
    Parameters
    ----------
    fruit_id_arr : array-like
        察象の果物のマスタIDを栌玍した配列。

    Returns
    -------
    fruit_price_arr : array-like
        果物の倀段を栌玍した配列。
    """
    # ...関数内容省略。
    return fruit_price_arr

リストなどの䞭身を明蚘する曞き方

  • たずえば、文字列を栌玍するリストなどの堎合、list of str、list of tupleずいった圢で型の個所が蚘茉されるこずがよくありたす。他にもlist of intだったり、list of dictsだったり様々
def get_fruit_price_list(fruit_id_list):
    """
    果物の倀段のリストを取埗する。
    
    Parameters
    ----------
    fruit_id_arr : list of int
        察象の果物のマスタIDを栌玍したリスト。

    Returns
    -------
    fruit_price_list : list of int
        果物の倀段を栌玍したリスト。
    """
    # ...関数内容省略。
    return fruit_price_list

その他

他にも、Referencesだったり、関数に応じお分かりやすいようにマヌクダりンのリスト的な衚蚘蚱容できる定数のリストだったりをしおいおたり、様々です。詳しくはNumPyの資料や、各ラむブラリのdocsringなど参考にしおください。

远蚘

チェック甚のラむブラリ䜜りたした。
NumPyスタむルのdocstringをチェックしおくれるLintを䜜りたした。


他にもPythonなどを䞭心に色々蚘事を曞いおいたす。そちらもどうぞ
今たでに投皿した䞻な蚘事たち

1180
1054
8

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1180
1054

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?