2010-01-08 4 views
70

Я пытаюсь выполнить некоторое наследование класса в Python. Я бы хотел, чтобы каждый класс и унаследованный класс имели хорошие docstrings. Так что я думаю, что для наследственного класса, я хотел бы его:Наследовать docstrings в наследовании класса Python

  • наследуют базовый класс
  • строки документации
  • возможно добавить соответствующую дополнительную документацию в строку документации

Есть ли (возможно, элегантные или pythonic) способ выполнения такого рода манипуляции с docstring в ситуации наследования класса? Как насчет множественного наследования?

ответ

32

Вы не единственный! Об этом некоторое время назад говорилось об comp.lang.python, и был создан рецепт. Проверьте это 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

Это удобно для метода наследования docstring метода родительского класса. Думаю, это было бы полезно во многих случаях. Я больше думал о docstring для всего класса, где я хотел бы наследовать и добавлять. –

+0

Ah, gotcha. В этом случае большая часть поколения doc уже делает это для вас. –

23

Вы можете конкатенации строк документации легко:

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 

Однако, это бесполезно. Большинство инструментов для создания документации (Sphinx и Epydoc включены) уже вытащит родительскую docstring, в том числе и для методов. Поэтому вам не нужно ничего делать.

+9

Действительно, большинство инструментов для документации делают это. Но встроенная функция help() не работает. – MarioVilas

+0

@MarioVilas: возможно, это ошибка, о которой следует сообщить? – naught101

3

Не особенно элегантно, но простой и прямой:

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

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

Сейчас:

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

Если вы хотите сделать это для 'Init docstring', есть ли способ сделать это в определении' Y'? Единственный способ, которым я смог это сделать, это использовать '__init __.__ doc__ = X .__ init __.__ doc__ +" Также еще один параметр "', следуя определению '__init__' в' Y', но это, похоже, путается с форматированием, вызывая дополнительные добавленные пробелы. – mgilbert

2

Смешанное турникет, который может сохранить и унаследованное строку документации синтаксис и предпочтительный порядок может быть:

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

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

С тем же выходом, что и у Алексея:

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

Тонкий лед: играет с строкой документации может сделать ваш модуль непригодным для использования с python -OO, ожидают некоторые из них:

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

Я написал custom_inherit предоставить некоторые простые, легкие инструменты веса для обработки наследования строки документации.

Он также поставляется с некоторыми красивыми стилями по умолчанию для слияния разных типов docstrings (например, с копиями Dupstring в формате Numpy, Google и RTST). Вы также можете легко создать свой собственный стиль.

Перекрывающиеся секции docstring будут относиться к разделу ребенка, иначе они будут объединены вместе с красивым форматированием.

Смежные вопросы