【问题标题】:How to allow parameters for a decorator while keep the function's signature at the same time?如何在保留函数签名的同时允许装饰器的参数?
【发布时间】:2015-12-21 04:16:28
【问题描述】:

我正在尝试编写一个装饰器,它会根据 kwargs 执行一些操作,同时我想保留函数签名。

这是我要通过的单元测试:

def test_test_deprecator(self):

    @test_deprecator("here is decorator message", 'z'):
    def some_method(x, y, z):
        return x + y

    self.assertEqual(some_method(2, 2, z=6), 4)

    # test the original function's signature
    argspec = inspect.getargspec(some_method)
    self.assertEqual(argspec.args, ["x", "y", "z"])

我写了类似的东西:

import decorator

def test_decorator(message, args_name):

    @decorator.decorator
    def _test_docorator(f, *args, **kwargs):
        if args_name in kwargs:
            print(message)
        return f(*args, **kwargs)

    return _test_docorator

单元测试可以通过,但是没有输出信息,因为kwargs一直是空的。

有谁知道如何做到这一点?

【问题讨论】:

    标签: python decorator


    【解决方案1】:

    我不确定@decorator.decorator 在你的代码中的作用是什么,但这里有一个装饰器在做你描述的事情:

    def test_decorator(message, arg_name):
        def _test_decorator(f):
            def wrapped_f(*args, **kwargs):
                if arg_name in kwargs:
                    print(message)
                return f(*args, **kwargs)
            return wrapped_f
        return _test_decorator
    

    更新答案:

    我学到了一些关于装饰器的研究。不过,简而言之,我认为使用 wrapt 模块对您有用:

    def test_decorator(message, arg_name):
        @wrapt.decorator
        def wrapped_f(f, instance, args, kwargs):
            if arg_name in kwargs:
                print(message)
            return f(*args, **kwargs)
        return wrapped_f
    

    测试代码:

    @test_decorator('found it', 'y')
    def foo(x="bad", y="dog"):
        print("x={}, y={}".format(x, y))
    
    def bar(x="bad", y="dog"):
        print("x={}, y={}".format(x, y))
    
    print ("foo argspec={}".format(inspect.getargspec(foo)))
    print ("bar argspec={}".format(inspect.getargspec(bar)))
    
    foo(y='cat')
    

    输出:

    foo argspec=ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=('bad', 'dog'))
    bar argspec=ArgSpec(args=['x', 'y'], varargs=None, keywords=None, defaults=('bad', 'dog'))
    found it
    x=bad, y=cat
    

    【讨论】:

    • 我想保留函数签名,这意味着当我使用“argspec = inspect.getargspec(fn)”时,它会为 fn 获取 args。
    • 抱歉,我更了解装饰器的一些细节以及您现在所问的问题。我更新了我的答案。
    • 不,这不好用。使用@wrapt.decorator,kwargs 仍然是空的,而 args 成为一个 dict,这甚至在运行 f(*args, **kwargs) 时会导致错误。
    • 我添加了我的测试代码和输出。它绝对看起来对我有用。
    • 你运行的是python2还是python3?
    猜你喜欢
    • 2010-09-13
    • 1970-01-01
    • 2020-03-31
    • 2015-08-14
    • 2020-05-08
    • 2017-07-10
    • 1970-01-01
    • 1970-01-01
    • 2019-03-11
    相关资源
    最近更新 更多