简体   繁体   中英

Using decorators to supply new args, kwargs

I have done some research about decorators, mainly about typical use-cases. It turned out that in majority of cases, they act as validators, timers, permission checkers - pretty transparent stuff. I was wondering if it would be pythonic to use them to precalculate and supply some variables to decorated function.

I've on my mind situation like this:

Decorator:

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:

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)

Usage:

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

As you can see fn1 and fn2 methods are doing almost same thing (calling __handle_data method), but with different var . Variable var depends on called function name. Calling fn1 results with var=fn1_operator and so on. Having in my mind the Zen of Python:

Simple is better than complex.

I'm having doubts about that being pythonic.

In the other hand, without that decorator, my code would have a lot of repetitions:

@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)

Is it correct? What should I change?

I wouldn't use a decorator here; I'd write a function that returns a closure over the specific data instead.

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')

(I didn't test, but I'm pretty sure it works the same if you decorate the closure as shown, or simply return an undecorated function and write fn1 = staticmethod(make_test('fn1')) , etc.)


With a decorator that focuses on the what is common , it might look like

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'

which has the same behavior, but is less clear as to the intent. Too much is hidden in the decorator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM