撰写时扩展或覆盖文档字符串 类

Extending or overwriting a docstring when composing classes

我有一个 class 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)

class 借鉴自 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" 会去哪里?

我不清楚 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对象。


装饰函数需要 return 一个可调用对象,但考虑到我们不需要改变 add 函数的行为,我们可以 return 参数它被传递给装饰器,所以给定装饰器函数...

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

显然,固定的文档字符串在这里用处不大,所以我们需要参数化装饰器,这有点复杂。

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

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

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)

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