2010-01-08 5 views
70

J'essaye de faire un peu d'héritage de classe en Python. Je voudrais que chaque classe et classe héritée ait de bonnes docstrings. Je pense donc que pour la classe héritée, je voudrais à:Hériter des docstrings dans l'héritage de classe Python

  • Hériter la classe de base docstring
  • append peut-être des documents supplémentaires pertinents pour la docstring

Y at-il (peut-être élégant ou pythonic) façon de faire ce genre de manipulation docstring dans une situation d'héritage de classe? Que diriez-vous pour l'héritage multiple?

Répondre

32

Vous n'êtes pas le seul! Il y a quelque temps, il y a eu une discussion sur comp.lang.python, et une recette a été créée. Vérifiez-le here.

""" 
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 
+0

C'est très bien pour une méthode d'hériter de la docstring de la classe parente. Ce serait utile dans de nombreux cas, je pense. Je pensais plus à la docstring pour toute la classe, où j'aimerais hériter et ajouter. –

+0

Ah, chéri. Dans ce cas, la plupart des doc-generation le font déjà pour vous. –

23

Vous pouvez concaténer les docstrings facilement:

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 

Cependant, 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. Donc vous n'avez rien à faire.

+9

En effet, la plupart des outils de documentation le font. Mais la fonction intégrée help() ne fonctionne pas. – MarioVilas

+0

@MarioVilas: c'est peut-être un bug qui devrait être rapporté? – naught101

3

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

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(). 
+0

Si vous voulez aussi faire cela pour le 'Init docstring', y a-t-il un moyen de le faire dans la définition de' Y'? La seule façon dont j'ai pu le faire est d'utiliser '__init __.__ doc__ = X .__ init __.__ doc__ +" Aussi un autre param "suivant la définition de' __init__' dans "Y" mais cela semble déranger le formatage espaces ajoutés. – mgilbert

2

Un stile mixte qui peut préserver à la fois la syntaxe docstring 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(). 

glace mince: jouer avec docstring peut rendre votre module inutilisable avec python -OO, attendez un peu:

TypeError: cannot concatenate 'str' and 'NoneType' objects 
-1

j'ai écrit custom_inherit pour fournir des outils simples, poids léger pour la gestion de l'héritage docstring.

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

Les sections docstring qui se chevauchent se reporteront à la section enfant, sinon elles seront fusionnées avec un formatage agréable.

Questions connexes