【问题标题】:Python decorator (closure version) that preserves signature保留签名的 Python 装饰器(闭包版本)
【发布时间】:2019-03-11 06:51:14
【问题描述】:

我的装饰器是“闭包式”;它在返回装饰函数之前做了一些工作。

借用这个著名的问题:Preserving signatures of decorated functions

def args_as_ints(f):

    time.sleep(1) # hard at work

    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g

functools.wraps 在 Python 2 中不保留签名。

from functools import wraps

def args_as_ints(f):

    time.sleep(1) # hard at work

    @wraps(f) 
    def g(*args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)
    return g


@args_as_ints
def funny_function(x, y, z=3):
    """Computes x*y + 2*z"""
    return x*y + 2*z

help(funny_function)

表演

Help on function funny_function in module __main__:

funny_function(*args, **kwargs)
    Computes x*y + 2*z

decorator 模块似乎不支持这种风格的装饰器。

还相关:Preserve Signature in Decorator python 2

【问题讨论】:

  • 你读过关于functools.wraps的部分吗?
  • 请澄清。你的问题是什么?你的装饰器在我的机器上工作正常:ideone.com/9RajlT。请注意,这个著名的问题已有 10 年历史,因此它可能会推荐不再需要的技术。
  • @NilsWerner:哪一部分?我试过了,它不保留签名
  • 请尝试修改您的问题
  • 啊抱歉,我错过了你的意思...

标签: python python-2.7 decorator


【解决方案1】:

您可以使用wrapt 模块。

请记住,wrapt 装饰器的接口与标准 python 装饰器不同。我强烈推荐阅读wrapt documentation。不管怎样,这是你的装饰器的基本实现wrapt.decorator

import wrapt

def args_as_ints(f):
    time.sleep(1) # hard at work

    @wrapt.decorator
    def g(f, instance, *args, **kwargs):
        args = [int(x) for x in args]
        kwargs = dict((k, int(v)) for k, v in kwargs.items())
        return f(*args, **kwargs)

    return g(f)  # apply the decorator to the function

请注意,我的实现完全忽略了 instance 参数,因此对于实例方法将无法正常工作。

不过,它确实保留了装饰函数的签名:

Help on function funny_function in module __main__:

funny_function(x, y, z=3)
    Computes x*y + 2*z

【讨论】:

    【解决方案2】:

    设法在这里找到答案:https://decorator.readthedocs.io/en/latest/tests.documentation.html#dealing-with-third-party-decorators

    def args_as_ints(f):
    
        time.sleep(1)
    
        def g(*args, **kwargs):
            args = [int(x) for x in args]
            kwargs = dict((k, int(v)) for k, v in kwargs.items())
            return f(*args, **kwargs)
    
        return decorator.FunctionMaker.create(
            f, 'return decfunc(%(signature)s)',
            dict(decfunc=g, __wrapped__=f))
    

    【讨论】:

      猜你喜欢
      • 2017-07-10
      • 1970-01-01
      • 2010-09-13
      • 1970-01-01
      • 2018-07-22
      • 1970-01-01
      • 1970-01-01
      • 2020-05-08
      • 1970-01-01
      相关资源
      最近更新 更多