web-dev-qa-db-ja.com

Pythonでクラス属性を文書化する方法は?

私は、その属性が一般にアクセスできるように意図された軽量クラスを書いていますが、特定のインスタンス化でのみオーバーライドされることもあります。 Pythonクラス属性のdocstringを作成するための言語、または任意の種類の属性については、その点については規定されていません。これらの属性を文書化する方法はありますか?私はこのようなことをしています:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
    """

    flight_speed = 691
    __doc__ += """
        flight_speed (691)
          The maximum speed that such a bird can attain.
    """

    nesting_grounds = "Raymond Luxury-Yacht"
    __doc__ += """
        nesting_grounds ("Raymond Luxury-Yacht")
          The locale where these birds congregate to reproduce.
    """

    def __init__(self, **keyargs):
        """Initialize the Albatross from the keyword arguments."""
        self.__dict__.update(keyargs)

これにより、最初の標準docstringセクションを含むクラスのdocstringと、__doc__への拡張割り当てによって各属性に追加された行が生成されます。

このスタイルは docstringスタイルガイドライン で明示的に禁止されているようには見えませんが、オプションとして言及されていません。ここでの利点は、定義と一緒に属性を文書化する方法を提供すると同時に、提示可能なクラスdocstringを作成し、docstringからの情報を繰り返すコメントを記述する必要がないことです。私は実際に属性を2回書く必要があることにいらいらします。少なくともデフォルト値の重複を避けるために、docstringの値の文字列表現の使用を検討しています。

これは、アドホックコミュニティの慣習に対する凶悪な違反ですか?大丈夫ですか?もっと良い方法はありますか?たとえば、属性の値とdocstringを含むディクショナリを作成し、クラス宣言の最後に向かってクラス__dict__とdocstringに内容を追加できます。これにより、属性名と値を2回入力する必要が軽減されます。 edit:この最後のアイデアは、実際には不可能であり、少なくともデータからクラス全体を動的に構築することなしではないと思います。それをする他の理由がない限り、アイデア。

私はpythonが初めてであり、コーディングスタイルの詳細をまだ検討中なので、無関係な批評も歓迎します。

97
intuited

混乱を避けるために:propertyという用語は、Pythonでは 特定の意味 を持っています。あなたが話しているのは、私たちが呼ぶものです class attributes それらは常にクラスを通じて実行されるため、クラスのdoc文字列内でドキュメント化することが理にかなっています。このようなもの:

class Albatross(object):
    """A bird with a flight speed exceeding that of an unladen swallow.

    Attributes:
        flight_speed     The maximum speed that such a bird can attain.
        nesting_grounds  The locale where these birds congregate to reproduce.
    """
    flight_speed = 691
    nesting_grounds = "Throatwarbler Man Grove"

あなたの例のアプローチよりも、目にはずっと簡単だと思います。属性値のコピーをドキュメント文字列に表示したい場合は、各属性の説明の横または下に配置します。

Pythonでは、doc文字列は単にソースコードの注釈ではなく、文書化するオブジェクトの実際のメンバーであることに注意してください。クラス属性変数はオブジェクトそのものではなく、オブジェクトへの参照であるため、独自のドキュメント文字列を保持する方法はありません。 「実際にここにあるもの」ではなく、「ここに何をすべきか」を説明するために、参照のdoc文字列のケースを作成できると思いますが、それを含むクラスのdoc文字列でそれを行うのは簡単です。

72
ʇsәɹoɈ

PEP257:Docstring Conventionsのセクション What is a docstring に記載されています:

Pythonコード内の他の場所で発生する文字列リテラルは、ドキュメントとしても機能します。Pythonバイトコードコンパイラによって認識されず、ランタイムオブジェクト属性としてアクセスできません。 __doc__に割り当てられていませんが、ソフトウェアツールによって2種類の余分なdocstringが抽出される場合があります。

モジュール、クラス、または__init__メソッドのトップレベルでの単純な割り当ての直後に発生する文字列リテラルは、「属性docstrings」と呼ばれます。

これについては、PEP 258:Attribute docstringsで詳しく説明されています。上記の「sәɹoɈ」で説明したように。属性は__doc__を所有できるオブジェクトではないため、help()またはpydocには表示されません。これらのdocstringは、生成されたドキュメントにのみ使用できます。

Sphinxでは directive autoattribute で使用されます

Sphinxは、割り当ての前の行にコメントを使用するか、割り当てに続く特別なコメント、または自動ドキュメント化される定義の後のdocstringを使用できます。

26
marcz

この結果、プロパティを悪用する可能性があります。プロパティには、getter、setter、deleter、、docstringが含まれます。単純に、これは非常に冗長になります。

class C:
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """Docstring goes here."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

次に、C.xに属するdocstringがあります。

In [24]: print(C.x.__doc__)
Docstring goes here.

多くの属性に対してこれを行うのは面倒ですが、ヘルパー関数mypropを想定できます。

def myprop(x, doc):
    def getx(self):
        return getattr(self, '_' + x)

    def setx(self, val):
        setattr(self, '_' + x, val)

    def delx(self):
        delattr(self, '_' + x)

    return property(getx, setx, delx, doc)

class C:
    a = myprop("a", "Hi, I'm A!")
    b = myprop("b", "Hi, I'm B!")

In [44]: c = C()

In [46]: c.b = 42

In [47]: c.b
Out[47]: 42

In [49]: print(C.b.__doc__)
Hi, I'm B!

次に、Pythonを対話的に呼び出すhelpは次のようになります。

Help on class C in module __main__:

class C
 |  Data descriptors defined here:
 |  
 |  a
 |      Hi, I'm A!
 |  
 |  b
 |      Hi, I'm B!

私はあなたが望んでいるものとほぼ同じであると思う。

編集:内部名は関係ないので、mypropに最初の引数を渡す必要をおそらく避けることができることに気付きました。後続のmypropの呼び出しが何らかの方法で互いに通信できる場合、長くてありそうもない内部属性名を自動的に決定できます。これを実装する方法はあると確信していますが、それが価値があるかどうかはわかりません。

11
gerrit