签名更改装饰器:正确记录附加参数

vik*_*ngr 5 python python-decorators

假设我有一个自定义装饰器,我希望它能够正确处理装饰函数的文档字符串。问题是:我的装饰器添加了一个参数。

from functools import wraps

def custom_decorator(f):
    @wraps(f)
    def wrapper(arg, need_to_do_more):
        '''
        :param need_to_do_more: if True: do more
        '''
        args = do_something(arg)

        if need_to_do_more:
            args = do_more(args)

        return f(args)

    return wrapper
Run Code Online (Sandbox Code Playgroud)

您可以看到参数实际上并未传递给装饰函数,而是由包装器使用 - 这在这里可能相关,也可能不相关。

如何正确处理记录附加参数?包装器接受额外的参数是一个好习惯,还是我应该避免它?

或者我应该使用不同的解决方案,例如:

  • 使包装器成为一个简单的高阶函数,它调用的函数作为第三个参数传递
  • 将包装器重构为两个独立的函数?

Jac*_*man 2

如果期望装饰的结果始终为该参数提供相同的内容,我建议将其设为参数化装饰器。我猜你已经想到了这一点,但还是需要说出来。

除此之外,我绝对建议将其分成两部分,就像您的第二个建议一样。然后装饰器的用户可以提供使用两个不同装饰器的“重载”版本(不是真正重载,因为它们需要不同的名称)。

另一种可能的选择是为参数指定默认值。

最后,如果您只是必须保持原样,则需要将新参数文档附加到包装器定义__doc__ 之后的末尾。

所以你的例子(缩短)看起来像这样:

def custom_decorator(f):
    @wraps(f)
    def wrapper(arg, need_to_do_more):
        ...

    wrapper.__doc__ += "/n:param need_to_do_more: if True: do more"
    return wrapper
Run Code Online (Sandbox Code Playgroud)

这是因为@wraps(f)装饰器用 's 替换了'swrapper文档f。之后添加它实际上会将两者结合起来。

沿着这些思路的另一个选项是记录custom_decorator,以便它表明包装的方法需要将参数添加到其文档中。这以及装饰器的拆分,给用户带来了负担,但它们使意图更加明确(“......显式优于隐式......” - Zen of Python)