【问题标题】:Inherit docstrings in Python class inheritance在 Python 类继承中继承文档字符串
【发布时间】:2010-01-08 04:45:11
【问题描述】:

我正在尝试在 Python 中进行一些类继承。我希望每个类和继承的类都有好的文档字符串。所以我认为对于继承的类,我希望它:

  • 继承基类文档字符串
  • 可能会将相关的额外文档附加到文档字符串中

在类继承情况下是否有任何(可能是优雅的或 Pythonic 的)方法来进行这种文档字符串操作?多继承呢?

【问题讨论】:

  • 我无法回答,因为这个问题不幸被关闭了,但是从 Python 3.5 开始,inspect.getdoc 将搜索继承树,直到找到一个文档字符串。
  • this answer

标签: python inheritance documentation


【解决方案1】:

你不是唯一一个!不久前在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 

【讨论】:

  • 对于继承父类方法的文档字符串的方法来说,这很好。我认为这在很多情况下都会很有用。我在想更多关于整个类的文档字符串,我想继承和追加。
  • 啊,明白了。在这种情况下,大多数 doc-generation 已经为您做到了。
【解决方案2】:

您可以轻松地连接文档字符串:

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

然而,那是没有用的。大多数文档生成工具(包括SphinxEpydoc)已经提取父文档字符串,包括方法。所以你不需要做任何事情。

【讨论】:

  • 确实,大多数文档工具都是这样做的。但是内置的 help() 函数没有。
  • @MarioVilas:也许这是一个应该报告的错误?
  • Sphinx 似乎没有为我这样做,也许是因为我的父母是“私人”,也就是名字以下划线开头。
【解决方案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().

【讨论】:

  • 如果您也想为Init docstring 这样做,有没有办法在Y 的定义中做到这一点?我能够做到这一点的唯一方法是在Y 中的__init__ 定义之后使用__init__.__doc__ = X.__init__.__doc__ + " Also another param",但这似乎与格式混淆,导致额外添加空格。
【解决方案4】:

可以保留继承的文档字符串语法和首选顺序的混合阶梯可以是:

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 的输出相同:

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

薄冰:使用 docstring 可能会使您的模块无法使用 python -OO,期待一些:

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

【讨论】:

    【解决方案5】:

    我写了custom_inherit 来提供一些简单、轻量级的工具来处理文档字符串继承。

    它还带有一些不错的默认样式,用于合并不同类型的文档字符串(例如 Numpy、Google 和 reST 格式的文档字符串)。你也可以很容易地提供自己的风格。

    重叠的文档字符串部分将遵循子部分,否则它们会以良好的格式合并在一起。

    【讨论】:

      【解决方案6】:

      这是一个非常古老的线程。但是,如果有人正在寻找一种简单的方法,您可以使用 __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]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-12-27
        • 2016-11-30
        • 2012-10-06
        • 2021-07-02
        • 2012-12-05
        • 2012-01-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多