基于class属性更改装饰器中类方法的docstring

时间:2017-11-22 16:28:24

标签: python python-sphinx python-decorators

让我们从这开始:

class Example(object):

    change_docstring = True

    @add_to_docstring(" (additional content!)")
    def example_method(self):
        """Example docstring."""
        pass

我想要做的是允许@add_to_docstring装饰器将其参数字符串附加到 方法的docstring中{{1} } attribute是change_docstring。我想要将任何其他内容传递给装饰器。

这个解决方案有效,但它并不是我想要的。

True

让我解释一下。

上述解决方案仅在执行def add_to_docstring(text): def decorator(original_method): def wrapper(self): """wrapper docstring.""" wrapper.__doc__ = original_method.__doc__ if self.change_docstring: wrapper.__doc__ += text return original_method(self) return wrapper return decorator 时更改文档字符串。加载类,方法等时,docstring不会改变。

example_method

这就是我想要的上述命令的输出:

>>> Example.example_method.__doc__
"wrapper docstring."
>>>
>>> Example().example_method()
>>> Example.example_method.__doc__
"Example docstring. (additional content!)"

同样,我不想将任何其他内容传递给装饰器。

更新

为了进一步说明,这是为了允许装饰器更改方法的文档字符串,并使该更改反映在Sphinx生成的文档中。 Sphinx加载所有内容并收集文档字符串,但它不再做任何事情。

根据选定的解决方案,我在decorators模块中添加了一个模块变量,并公开了一个方法来禁用装饰器中的文档字符串更改功能。为了普遍禁用该功能,我在我的Sphinx >>> Example.example_method.__doc__ "Example docstring. (additional content!)" 文件中调用了禁用功能,如下所示:

conf.py

然后可以在项目中的任何方法上使用装饰器,并且可以启用或禁用文档字符串更改。

2 个答案:

答案 0 :(得分:1)

Martijn Pieter's answer至&#34中所述;从类定义中的列表理解中访问类变量"如果您在班级的新范围内,则无法访问类属性。该答案主要关注类范围中的理解和生成器表达式,但这同样适用于普通函数,包括装饰器。

解决这个问题的一个简单方法是使change_docstring成为全局变量,并在类之前定义它,以便您可以在逐个类的基础上轻松设置它。另一个选择是让它成为装饰者的一个参数,但是你说你不喜欢这样做。这是一个适用于Python 2和DSP的简短演示。 3。

def add_to_docstring(text):
    def decorator(original_method):
        def wrapper(self):
            return original_method(self)
        wrapper.__doc__ = original_method.__doc__
        if change_docstring:
            wrapper.__doc__ += text
        return wrapper
    return decorator

change_docstring = True
class Example(object):
    @add_to_docstring(" (additional content!)")
    def example_method(self):
        """Example docstring."""
        pass

change_docstring = False
class Other(object):
    @add_to_docstring(" (more content!)")
    def example_method(self):
        """Other docstring."""
        pass

print(Example.example_method.__doc__)
print(Other.example_method.__doc__)

<强>输出

Example docstring. (additional content!)
Other docstring.

答案 1 :(得分:1)

装饰并标记方法

我们不需要在这里关心函数签名,无论它是绑定还是未绑定 - 我们只是将一个带有附加文本的属性放在函数对象上。无论它是什么。

def add_to_docstring(text):
    def func(f):
        f.__add_to_docstring = text
        return f
    return func

装饰该类以表明我们希望标记的方法得到尊重

通过使用类装饰器,我们可以表明我们希望遵守标记方法并更改文档字符串。我们扫描可调用对象,检查它们是否是包含要添加到docstring的内容的装饰对象,并在返回具有不同函数docstrings的新类型之前进行适当的更改。

def change_docstrings(cls):
    for obj in vars(cls).values():
        if callable(obj) and hasattr(obj, '__add_to_docstring'):
            obj.__doc__ = (obj.__doc__ or '') + obj.__add_to_docstring
            del obj.__add_to_docstring
    return cls

将它们放在一起

@change_docstrings
class Example:
    @add_to_docstring('(cabbage!)')
    def example(self):
        """ something here """
        pass

检查Example.example.__doc__我们得到 - ' something here (cabbage!)',如果您删除@change_docstrings类装饰器,则不会有任何更改。

请注意,这会将change_docstrings移出类,无论您是否装饰,但是,它允许构造如下:

unchanged_docstrings = Example
changed_docstrings = change_docstrings(Example)