首页 > 解决方案 > 使用装饰器提供新的 args、kwargs

问题描述

我做过一些关于装饰器的研究,主要是关于典型的用例。事实证明,在大多数情况下,它们充当验证器、计时器、权限检查器——非常透明的东西。我想知道使用它们来预先计算并为装饰函数提供一些变量是否是 Pythonic。

我的想法是这样的:

装饰师:

def foo(fn):
    @functools.wraps(fn)
    def wrapper(*args, **kwargs):
        fn_name = fn.__name__
        var = Test._do_something(Test.store_dict[fn_name])
        kw_args = {**kwargs, **dict(var=var)}
        return fn(*args, **kw_args)
    return wrapper

班级:

class Test:
    store_dict = dict(fn1='fn1_operator',
                      fn2='fn2_operator')

    @staticmethod
    @foo
    def fn1(dummy_data, **kwargs):
        return Test.__handle_data(dummy_data=dummy_data,
                                  **kwargs)
    @staticmethod
    @foo
    def fn2(dummy_data, **kwargs):
        return Test.__handle_data(dummy_data=dummy_data,
                                  **kwargs)

    @staticmethod
    def _do_something(var):
        return var

    @staticmethod
    def __handle_data(dummy_data, var):
        return (dummy_data, var)

用法:

test_instance = Test()
test_instance.fn1(dummy_data='test')

正如你所看到的fn1fn2方法在做几乎相同的事情(调用__handle_data方法),但使用不同的var. 变量var取决于被调用的函数名。调用fn1结果var=fn1_operator以此类推。在我心中有 Python 之禅:

简单胜于复杂。

我怀疑那是pythonic。

另一方面,如果没有那个装饰器,我的代码会有很多重复:

@staticmethod
def fn1(dummy_data):
    var = _do_something('fn1')
    return Test.__handle_data(dummy_data=dummy_data,
                              var=var)
@staticmethod
def fn2(dummy_data):
    var = _do_something('fn2')
    return Test.__handle_data(dummy_data=dummy_data,
                              var=var)

这是对的吗?我应该改变什么?

标签: python

解决方案


我不会在这里使用装饰器;我会编写一个函数来返回特定数据的闭包。

def make_test(arg):
    @staticmethod
    def _(dummy_data):
        var = _do_something(arg)
        return Test.__handle_data(dummy_data, var=var)
    return _

fn1 = make_test('fn1')
fn2 = make_test('fn2')

(我没有测试,但我很确定如果你如图所示装饰闭包,或者只是返回一个未装饰的函数并 writefn1 = staticmethod(make_test('fn1'))等,它的工作原理是一样的)


使用专注于共同点的装饰器,它可能看起来像

def foo(f):
    def _(dummy_data):
        var = _do_something(f())
        return Test.__handle_data(dummy_data, var=var)
    return _

@foo
def fn1(self):
    return 'fn1'


@foo
def fn2(self):
    return 'fn2'

它具有相同的行为,但对意图不太清楚。装饰器中隐藏了太多东西。


推荐阅读