Успадковувати документи у спадкуванні класу Python


97

Я намагаюся зробити успадкування класу в Python. Я хотів би, щоб кожен клас та успадкований клас мали хороші документи. Тому я думаю, що для успадкованого класу я хотів би:

  • успадкувати документацію базового класу
  • можливо, додати відповідну додаткову документацію до документації

Чи існує якийсь (можливо, елегантний чи пітонічний) спосіб здійснення такого роду маніпуляцій із документами у ситуації успадкування класу? Як щодо багаторазового успадкування?


2
Я не можу відповісти, оскільки питання, на жаль, було закрито, але станом на Python 3.5, inspect.getdocбуде шукати дерево спадкування, поки не знайде документ.
геррит

1
Дивіться цю відповідь .
геррит

Відповіді:


39

Ти не єдиний! Нещодавно comp.lang.pythonпро це йшла дискусія , і був створений рецепт. Перевірте тут .

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

Ви можете легко об’єднати документи:

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 ) вже буде витягувати батьківський документ, включаючи методи. Тож вам не потрібно нічого робити.


16
Дійсно, більшість інструментів документації це роблять. Але вбудована функція довідки () ні.
MarioVilas

2
@MarioVilas: можливо, це помилка, про яку слід повідомити?
naught101

Сфінкс, здається, не робить цього для мене, можливо, тому, що мій батько "приватний", а саме ім'я починається з підкреслення.
Gringo Suave

6

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

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

Якщо ви хочете зробити це і для того самого Init docstring, чи є спосіб це зробити у визначенні Y? Єдиний спосіб , яким я був в змозі зробити це , використовуючи __init__.__doc__ = X.__init__.__doc__ + " Also another param"після __init__визначення в , Yале це , здається, возитися з форматуванням, в результаті чого додаткові додані прогалини.
mgilbert

5

Змішаним стилем, який може зберегти як успадкований синтаксис документації, так і бажаний порядок може бути:

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

4

Я написав custom_inherit, щоб надати кілька простих, легких інструментів для обробки спадщини docstring.

Він також постачається з декількома приємними стилями за замовчуванням для об’єднання різних типів текстових рядків (наприклад, Numpy, Google та форматовані текстові рядки reST). Ви також можете дуже легко надати свій власний стиль.

Накладання розділів документації переноситься на розділ дитини, інакше вони поєднуються разом із приємним форматуванням.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.