web-dev-qa-db-fra.com

Hériter des docstrings dans Python

J'essaie de faire un héritage de classe en Python. J'aimerais que chaque classe et classe héritée ait de bonnes docstrings. Je pense donc que pour la classe héritée, j'aimerais:

  • hériter de la classe de base docstring
  • peut-être ajouter de la documentation supplémentaire pertinente à la docstring

Existe-t-il un moyen (éventuellement élégant ou Pythonique) de faire ce genre de manipulation de docstring dans une situation d'héritage de classe? Et pour l'héritage multiple?

85
Craig McQueen

Tu n'es pas le seul! Il y a eu une discussion sur comp.lang.python à ce sujet il y a quelque temps, et une recette a été créée. Vérifiez-le ici.

"""
doc_inherit decorator

Usage:

class Foo(object):
    def foo(self):
        "Frobber"
        pass

class Bar(Foo):
    @doc_inherit
    def foo(self):
        pass 

Now, Bar.foo.__doc__ == Bar().foo.__doc__ == Foo.foo.__doc__ == "Frobber"
"""

from functools import wraps

class DocInherit(object):
    """
    Docstring inheriting method descriptor

    The class itself is also used as a decorator
    """

    def __init__(self, mthd):
        self.mthd = mthd
        self.name = mthd.__name__

    def __get__(self, obj, cls):
        if obj:
            return self.get_with_inst(obj, cls)
        else:
            return self.get_no_inst(cls)

    def get_with_inst(self, obj, cls):

        overridden = getattr(super(cls, obj), self.name, None)

        @wraps(self.mthd, assigned=('__name__','__module__'))
        def f(*args, **kwargs):
            return self.mthd(obj, *args, **kwargs)

        return self.use_parent_doc(f, overridden)

    def get_no_inst(self, cls):

        for parent in cls.__mro__[1:]:
            overridden = getattr(parent, self.name, None)
            if overridden: break

        @wraps(self.mthd, assigned=('__name__','__module__'))
        def f(*args, **kwargs):
            return self.mthd(*args, **kwargs)

        return self.use_parent_doc(f, overridden)

    def use_parent_doc(self, func, source):
        if source is None:
            raise NameError, ("Can't find '%s' in parents"%self.name)
        func.__doc__ = source.__doc__
        return func

doc_inherit = DocInherit 
36
John Feminella

Vous pouvez concaténer facilement les docstrings:

class Foo(object):
    """
    Foo Class.
    This class foos around.
    """
    pass

class Bar(Foo):
    """
    Bar class, children of Foo
    Use this when you want to Bar around.
    parent:
    """ 
    __doc__ += Foo.__doc__
    pass

Mais cela est inutile. La plupart des outils de génération de documentation ( Sphinx et Epydoc inclus) tireront déjà la docstring parent, y compris pour les méthodes. Vous n'avez donc rien à faire.

33
nosklo

Pas particulièrement élégant, mais simple et direct:

class X(object):
  """This class has a method foo()."""
  def foo(): pass

class Y(X):
  __doc__ = X.__doc__ + ' Also bar().'
  def bar(): pass

Maintenant:

>>> print Y.__doc__
This class has a method foo(). Also bar().
6
Alex Martelli

Un stile mixte qui peut conserver à la fois la syntaxe de la chaîne de documents héritée et l'ordre préféré peut être:

class X(object):
  """This class has a method foo()."""
  def foo(): pass

class Y(X):
  """ Also bar()."""
  __doc__ = X.__doc__ + __doc__
  def bar(): pass

Avec la même sortie que celle d'Alex:

>>> print Y.__doc__
This class has a method foo(). Also bar().

Thin ice: jouer avec docstring peut rendre votre module inutilisable avec python -OO, attendez-vous à:

TypeError: cannot concatenate 'str' and 'NoneType' objects
5
naufraghi

J'ai écrit custom_inherit pour fournir des outils simples et légers pour gérer l'héritage de docstring.

Il est également livré avec certains styles par défaut Nice pour fusionner différents types de docstrings (par exemple Numpy, Google et docSTings formatés reST). Vous pouvez également fournir votre propre style très facilement.

Les sections de docstring qui se chevauchent se reportent à la section de l'enfant, sinon elles sont fusionnées avec le formatage Nice.

1
Ryan Soklaski