简体   繁体   English

继承 Python class inheritance 中的文档字符串

[英]Inherit docstrings in Python class inheritance

I'm trying to do some class inheritance in Python.我正在尝试在 Python 中做一些 class inheritance。 I'd like each class and inherited class to have good docstrings.我希望每个 class 和继承的 class 都有好的文档字符串。 So I think for the inherited class, I'd like it to:所以我认为对于继承的 class,我希望它:

  • inherit the base class docstring继承基础 class 文档字符串
  • maybe append relevant extra documentation to the docstring也许 append 文档字符串的相关额外文档

Is there any (possibly elegant or pythonic) way of doing this sort of docstring manipulation in a class inheritance situation?在 class inheritance 情况下,是否有任何(可能是优雅的或 Pythonic 的)方法来执行这种文档字符串操作? How about for multiple inheritance?多个 inheritance 怎么样?

You can concatenate the docstrings easily:您可以轻松连接文档字符串:

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

However, that is useless.然而,这是没有用的。 Most documentation generation tool ( Sphinx and Epydoc included) will already pull parent docstring, including for methods.大多数文档生成工具(包括SphinxEpydoc )已经拉取父文档字符串,包括方法。 So you don't have to do anything.所以你什么都不用做。

You're not the only one!你不是唯一一个! There was a discussion on comp.lang.python about this a while ago, and a recipe was created.不久前在comp.lang.python上有一个关于这个的讨论,并创建了一个配方。 Check it out 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 

A mixed stile that can preserve both the inherited docstring syntax and the preferred ordering can be:可以保留继承的文档字符串语法和首选顺序的混合 stile 可以是:

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

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

With the same output as Alex's one:与亚历克斯的输出相同:

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

Thin ice: playing with docstring can make your module unusable with python -OO , expect some:薄冰:使用 docstring 会使你的模块无法使用python -OO ,期待一些:

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

Not particularly elegant, but simple and direct:不是特别优雅,但简单直接:

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

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

Now:现在:

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

I wrote custom_inherit to provide some simple, light weight tools for handling docstring inheritance.我编写了custom_inherit来提供一些简单、轻量级的工具来处理文档字符串继承。

It also comes with some nice default styles for merging different types of docstrings (eg Numpy, Google, and reST formatted docstrings).它还带有一些很好的默认样式,用于合并不同类型的文档字符串(例如 Numpy、Google 和 reST 格式的文档字符串)。 You can also provide your own style very easily.您也可以非常轻松地提供自己的风格。

Overlapping docstring sections will defer to the child's section, otherwise they are merged together with nice formatting.重叠的文档字符串部分将遵循子部分,否则它们会以良好的格式合并在一起。

It is a very old thread.这是一个非常古老的线程。 But If anyone is looking for a simple way, you can do this with __init_subclass__ which is called whenever you inherit that class.但是,如果有人正在寻找一种简单的方法,您可以使用 __init_subclass__ 来执行此操作,只要您继承该__init_subclass__ ,就会调用它。

def __init_subclass__(cls, **kwargs):
    super().__init_subclass__(**kwargs)
    parent_method_docstr = {}
    for i, v in ParentClass.__dict__.items():
        if v and callable(v) and v.__doc__ is not None:
            parent_method_docstr[i] = v.__doc__

    for i, v in cls.__dict__.items():
        if v and callable(v) and v.__doc__ is None and i in parent_method_docstr:
            v.__doc__ = parent_method_docstr[i]

Starting with Python 3.5, docstrings are now inherited if a subclass doesn't have any documentation.从 Python 3.5 开始,如果子类没有任何文档,则现在继承文档字符串。

You can use inspect.getdoc() accordingly:您可以相应地使用inspect.getdoc()

import inspect

class A:
  """Hello"""

class B(A):
  pass

class C(B):
  __doc__ = inspect.getdoc(B) + " World"

Do note that the builtin help function pulls recursively only for overridden functions but not for class docstring for some odd reason:请注意,由于某些奇怪的原因,内置帮助 function 仅针对被覆盖的函数而递归地提取 class 文档字符串:

class A:
  """Hello"""
  def test():
    """Testdoc"""

class B(A):
  def test():
    pass

>>> help(B.test)
... Testdoc ...
>>> help(B)
...  # No "Hello".

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM