web-dev-qa-db-ja.com

類似の関数間でDocstringを共有していますか?

まったく同じ説明を持つメソッドを持つさまざまなクラスがあると仮定しますが、同じ戻り値の型に対してコードの実行方法が少し異なります。

_class Foo:
    """This is the Foo class Docstring. It is a type of Bar source."""
    def getBar(self,pos):
        """
        This is the Bar method. 
        It calculates and returns the Bar field effect generated 
        by this source based on `pos`
        """   
        effect = pos + 1 
        return effect

class Waldo:
    """This is the Waldo class Docstring. It's also a type of Bar source."""
    def getBar(self,pos):
        """
        This is the Bar method. 
        It calculates and returns the Bar field effect generated 
        by this source based on `pos`
        """   
        effect = pos + 2 
        return effect
_

これは問題です。バーのソースが多数あるとすると、getBar()の説明を変更すると、すべてのソースに対して変更を繰り返す必要があるためです。

これらの両方で共有される単一のDocstringが存在するようにするにはどうすればよいですか?Foo.getBar()を変更すると、ツールチップのWaldo.getBar()の説明が変更されますか?

同じ効果を達成するために再構築または上書きする方法も歓迎されます。


私は この質問__doc__+=Foo.getBar().__doc__アプローチを試しましたが、信頼できないようです(たとえば、Spyderなどの環境を使用すると、ローカル変数として認識されます)。

4
lucasgcb

ツールによって、docstringへのアクセス方法は異なります。たとえば、このdocstringを提供する共通の基本クラスがあれば、一部のツールでは十分な場合がありますが、他のツールでは不十分な場合があります。

最も一般的なアプローチは、関数のdocstringをコピーするデコレータのようなfunctools.wraps()を定義することです。例:

def is_documented_by(original):
  def wrapper(target):
    target.__doc__ = original.__doc__
    return target
  return wrapper

class Waldo:
  @is_documented_by(Foo.getBar)
  def getBar():
    ...

しかし、これにはPythonコードを実行する必要があるため、Pylintのような静的アナライザーはこれを好まない場合があります。最適な解決策は、使用するツールによって異なります。

4
amon

このために私が実装したアプローチは次のとおりです。

class Field_Sampler:
    def getBar(self,pos):
        """
        This is the Bar method. 
        It calculates and returns the Bar field effect generated 
        by this source based on `pos`
        """   
        import warnings
        warnings.warn(
            "called getBar method is not implemented in this class,"
            "returning 0", RuntimeWarning)
        return 0


class Foo(Field_Sampler):
    """This is the Foo class Docstring. It is a type of Bar source."""
    def getBar(self,pos): 
        effect = pos + 1 
        return effect

class Waldo(Field_Sampler):
    """This is the Waldo class Docstring. It's also a type of Bar source."""
    def getBar(self,pos):
        effect = pos + 2 
        return effect

class Epsilon(Field_Sampler):
    """[WIP]This is the Epsilon class Docstring. It's also a type of Bar source."""
    pass

トップクラスには、docstringを含む関数プロトタイプがあります。クラスはこれを継承し、メソッドの実装定義をオーバーライドします。オーバーライドされた関数にdocstringがない場合、親のdocstringは、Sphinxを含むほとんどのdocインタープリターで使用されます。

これにより、構造を保持しながら(より多くのメソッドを含む)多数のクラスを設定し、静的アナライザーが異常動作するのを防ぐことができました。メソッドがまだ実装されていない場合、誰かがたまたまそれを呼び出した場合に警告をスローします。

0
lucasgcb