Наследовать docstrings в наследовании класса Python
Я пытаюсь сделать некоторое наследование класса в Python. Я бы хотел, чтобы каждый класс и унаследованный класс имели хорошие docstrings. Поэтому я считаю, что для унаследованного класса мне бы хотелось:
- наследует базовый класс docstring
- возможно добавить соответствующую дополнительную документацию в docstring
Есть ли какой-нибудь (возможно, элегантный или питонический) способ выполнения такого рода манипуляции с docstring в ситуации наследования класса? Как насчет множественного наследования?
Ответы
Ответ 1
Ты не единственный! Об этом некоторое время назад обсуждалась 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
Ответ 2
Вы можете легко конкатенать 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
Однако это бесполезно. Большинство инструментов для создания документации (Sphinx и Epydoc включено) уже вытащит родительскую docstring, в том числе для методов. Поэтому вам не нужно ничего делать.
Ответ 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().
Ответ 4
Смешанная структура, которая может сохранять как унаследованный синтаксис docstring, так и предпочтительный порядок, может быть:
class X(object):
"""This class has a method foo()."""
def foo(): pass
class Y(X):
""" Also bar()."""
__doc__ = X.__doc__ + __doc__
def bar(): pass
С тем же выходом, что и Alex one:
>>> print Y.__doc__
This class has a method foo(). Also bar().
Тонкий лед: игра с docstring может сделать ваш модуль непригодным с помощью python -OO
, ожидайте некоторых:
TypeError: cannot concatenate 'str' and 'NoneType' objects
Ответ 5
Я написал custom_inherit, чтобы предоставить простые, легкие инструменты для обработки наследования docstring.
Он также содержит некоторые хорошие стили по умолчанию для слияния разных типов docstrings (например, Nump, Google и RTT форматированные docstrings). Вы также можете легко создать свой собственный стиль.
Перекрывающиеся секции docstring будут отложены к дочернему разделу, в противном случае они будут объединены вместе с хорошим форматированием.