当一个方法中有两个装饰器时,为啥 sphinx autodoc 会输出一个装饰器的文档字符串?

Posted

技术标签:

【中文标题】当一个方法中有两个装饰器时,为啥 sphinx autodoc 会输出一个装饰器的文档字符串?【英文标题】:Why does sphinx autodoc output a decorator's docstring when there are two decorators in a method?当一个方法中有两个装饰器时,为什么 sphinx autodoc 会输出一个装饰器的文档字符串? 【发布时间】:2017-09-18 14:07:53 【问题描述】:

使用 sphinx autodoc 我想为具有 @classproperty@classmethod 装饰器的方法生成文档。我得到了@classmethod 的文档,而不是方法的文档。如果我删除任何装饰器,一切都会正常工作。 类代码结构如下:

class Example(object):
    @classproperty
    @classmethod
    def example_method(cls):
       """Method description"""
       pass

类属性装饰器:

class classproperty(property):
    def __get__(self, obj, type=None):
        return self.fget.__get__(None, type)()

我正在使用以下方法生成文档:

.. autoclass:: Example
    :members:

【问题讨论】:

什么是classproperty?我们如何重现这个? 我已经用 classproperty 代码更新了这个问题,所以你现在可以重现它 【参考方案1】:

来自Sphinx documentation,

注意

如果您记录修饰的函数或方法,请记住 autodoc 通过导入模块并检查给定函数或方法的 doc 属性来检索其文档字符串。这意味着如果装饰器用另一个装饰函数替换了被装饰的函数,它必须将原始 doc 复制到新函数中。

从 Python 2.5 开始,functools.wraps() 可用于创建行为良好的装饰函数。

所以我认为这里的问题是你的装饰器在包装函数时删除了文档字符串。 wraps 应该可以帮助解决这个问题。

您可以按照Python documentation 中的模式来讨论该主题。对于您的用例,您可以这样做:

from functools import wraps

def classpropertymethod(f):
    @wraps(f)
    def wrapper(*args, **kwargs):
        return classproperty(classmethod(f(*args, **kwargs)))
    return wrapper

@classpropertymethod
def example_method(cls):
    """Method description"""
    pass

这应该会从example_method 正确传递文档字符串。

【讨论】:

以上是关于当一个方法中有两个装饰器时,为啥 sphinx autodoc 会输出一个装饰器的文档字符串?的主要内容,如果未能解决你的问题,请参考以下文章

Sphinx autodoc - 装饰器和 ReadTheDocs

使用类作为装饰器时,为啥 'self' 不在 args 中? [复制]

Typescript:使用装饰器时的类型推断

装饰器仅在装饰方法时有效,但在使用作为参数传递的方法调用装饰器时无效

如何让 sphinx 识别装饰的 python 函数

创建装饰器时保留元信息