【问题标题】:Extending or overwriting a docstring when composing classes编写类时扩展或覆盖文档字符串
【发布时间】:2016-06-30 13:55:25
【问题描述】:

我有一堂课MyClass

class MyClass(object):
    def __init__(self):
        pass

    def my_function(self, x):
        # MyClass.my_function.__doc__ is not writable!
        # Otherwise, I could just set it here.
        Origin.func(self, x)

类借用Origin:

class Origin(object):    
    def func(obj, x):
        """This is a function
        """
        # do stuff
        pass

如何自动将文档字符串从 Origin.func 复制到 MyClass.my_function 以便 Sphinx Autodoc 识别它?以及如何通过几个词来扩展原始文档字符串?

编辑:

Afaik,我不能在函数定义后更改 __doc__,因为那时 Sphinx 找不到它。或者如果有,“docfix”会去哪里?

【问题讨论】:

  • 您能否举一个不那么抽象的例子来说明您想要实现的目标? my_function.__doc__ = Origin.func.__doc__ + 'also this' 应该在 my_function 的定义结束后正常工作。
  • 我不确定如何让它更清楚——不过我编辑了我的问题。有帮助吗?
  • 哦,我明白了!我可以在类的定义之后写它。这确实有效!
  • 您应该能够在类中执行此操作,就在方法定义之后。但是,在一个不继承的类中有一个方法继承文档似乎很奇怪!
  • 它背后的想法是我想组合一个类(而不是继承),但有些方法只是从其他类中复制过来并稍作更正。因此,参数等都保持不变。我正在做的事情还有另一种方法吗?例如,我有一个to_latex 方法。在我的组合类中,完成了一些后处​​理(作为包装器),但调用与原始类相同。

标签: python python-sphinx composition docstring


【解决方案1】:

我不清楚 Sphinx 究竟是如何工作的,但假设它从 __doc__ 读取而不是解析源代码,那么有很多选项。


考虑一个更简单的例子......

def add(x, y):
    return x + y

...实际上与...相同

add = lambda x, y: x + y

在任何一种情况下,您都不能在其定义中引用符号add,因为此时尚未定义该符号。也不能引用符号add 最终引用的function 对象,因为它尚未创建。

因此,您只能修改add.__doc__符号已经定义...

def add(x, y):
    return x + y
add.__doc__ = 'This is my docstring'

...但这可能比我们想要的要冗长一些。


另一个选择是利用 Python 装饰器语法...

@my_decorator
def add(x, y):
    return x + y

...等价于...

def add(x, y):
    return x + y
add = my_decorator(add)

...也就是说,虽然它放在之前函数定义,它执行之后函数定义,所以你可以参考装饰器函数体内的function 对象。


装饰器函数需要返回一个可调用对象,但鉴于我们不需要改变add函数的行为,我们可以只返回传递给装饰器的参数,所以给定装饰器函数...

def set_fixed_docstring(func):
    func.__doc___ = 'This is my docstring'
    return func

...用作...

@set_fixed_docstring
def add(x, y):
    return x + y

...等价于...

def add(x, y):
    return x + y
add = set_fixed_docstring(add)

...或...

def add(x, y):
    return x + y
add.__doc__ = 'This is my docstring'
add = add

显然,固定的docstring在这里用处不大,所以我们需要对装饰器进行参数化,这有点复杂。

在这种情况下,我们需要我们的装饰器函数可以使用字符串参数调用,返回一个以目标函数作为参数的可调用对象。

最常见的方法是在装饰器函数中定义另一个函数,这样内部函数可以引用外部函数中定义的符号。所以函数...

def set_docstring_to(docstring):
    def wrapper(func):
        func.__doc___ = docstring
        return func
    return wrapper

...用作...

@set_docstring_to('This is my docstring')
def add(x, y):
    return x + y

...等价于...

def add(x, y):
    return x + y
add = set_docstring_to('This is my docstring')(add)

...归结为与以前相同的代码...

def add(x, y):
    return x + y
add.__doc__ = 'This is my docstring'
add = add

把所有这些放在一起,如果你要使用像...这样的装饰器

def copy_docstring_from(source):
    def wrapper(func):
        func.__doc__ = source.__doc__
        return func
    return wrapper

...那你就可以...

class Origin(object):
    def func(obj, x):
        """This is a function
        """
        # do stuff
        pass

class MyClass(object):
    def __init__(self):
        pass

    @copy_docstring_from(Origin.func)
    def my_function(self, x):
        # MyClass.my_function.__doc__ is not writable!
        # Otherwise, I could just set it here.
        Origin.func(self, x)

...应该用最少的代码达到预期的效果。

【讨论】:

  • “假设它从 __doc__ 读取而不是解析源” - 是的,autodoc 只是导入源代码并遍历对象以获取 __doc__ 属性.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-04
  • 2017-06-28
  • 1970-01-01
  • 2011-10-15
  • 2011-09-09
  • 1970-01-01
相关资源
最近更新 更多