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.