访问装饰函数的文档?

Access to documentation of a decorated function?

我正在开发一个 API,通过它我将模块的功能列表以及每个功能的文档传递给用户。为了访问我曾经做过的文档:

def foo(*args, **kwargs):
    """
    Foo documentation is here!
    """
    return None

print(foo.__doc__)
# Foo documentation is here!

现在我为其中一些函数添加了装饰器,__doc__ returns None 因为装饰器函数没有任何文档。

def decor_func(func):
    def wrap(*args, **kwargs):
        return func(*args, **kwargs)
    return wrap

@decor_func
def foo(*args, **kwargs):
    """
    Foo documentation is here!
    """
    return None

print(foo.__doc__)
# None

有什么方法可以访问修饰函数的文档吗?

您可以更新 wrap 函数的 __doc__ 属性:

def decor_func(func):
    def wrap(*args, **kwargs):
        return func(*args, **kwargs)
    
    # Set the decorated function `__doc__` attribute
    wrap.__doc__ = func.__doc__
    return wrap

@decor_func
def foo(*args, **kwargs):
    """
    Foo documentation is here!
    """
    return None

print(foo.__doc__)
# Foo documentation is here!

但是,最好的方法是使用 functools.wraps,这样您还可以复制其他属性,例如原始名称、模块和注释:

import functools

def decor_func(func):
    @functools.wraps(func)
    def wrap(*args, **kwargs):
        return func(*args, **kwargs)
    return wrap

@decor_func
def foo(*args, **kwargs):
    """
    Foo documentation is here!
    """
    return None

print(foo.__doc__)
# Foo documentation is here!

请注意,正如其他人指出的那样,您应该使用 functools.wraps 以便您的包装器“看起来”像它正在包装的函数,并将包装的函数添加到 __wrapped__ 属性。但是,请注意,您始终可以内省包装器的闭包以检索对原始函数的引用,因为它是包装器中的自由变量,因此将存储在闭包中:

>>> def decor_func(func):
...     def wrap(*args, **kwargs):
...         return func(*args, **kwargs)
...     return wrap
...
>>> @decor_func
... def foo(*args, **kwargs):
...     """
...     Foo documentation is here!
...     """
...     return None
...
>>> foo.__closure__
(<cell at 0x10e69da90: function object at 0x10e83a700>,)

所以,

>>> foo.__closure__[0].cell_contents.__doc__
'\n    Foo documentation is here!\n    '

但同样,您应该首先使用 functools.wraps。如果您无法控制装饰器,以上内容可能会有所帮助。