Is there a way to combine two decorators into one new decorator in python?
I realize I can just apply multiple decorators to a function, but I was curious as to whet
Decorators are just functions that take a function as input and return a new function. This:
@deco
def foo():
...
Is equivalent to this:
def foo():
...
foo = deco(foo)
In other words, the decorated function (foo
) is passed as an argument to the decorator, and then foo
is replaced with the return value of the decorator. Equipped with this knowledge, it's easy to write a decorator that combines two other decorators:
def merged_decorator(func):
return decorator2(decorator1(func))
# now both of these function definitions are equivalent:
@decorator2
@decorator1
def foo():
...
@merged_decorator
def foo():
...
It gets a little trickier if the decorators accept arguments, like these two:
@deco_with_args2(bar='bar')
@deco_with_args1('baz')
def foo():
...
You might wonder how these decorators are even implemented. It's actually pretty simple: deco_with_args1
and deco_with_args2
are functions that return another function decorator. Decorators with arguments are essentially decorator factories. The equivalent of this:
@deco_with_args('baz')
def foo():
...
Is this:
def foo():
...
real_decorator = deco_with_args('baz')
foo = real_decorator(foo)
In order to make a decorator that accepts arguments and then applies two other decorators, we have to implement our own decorator factory:
def merged_decorator_with_args(bar, baz):
# pass the arguments to the decorator factories and
# obtain the actual decorators
deco2 = deco_with_args2(bar=bar)
deco1 = deco_with_args1(baz)
# create a function decorator that applies the two
# decorators we just created
def real_decorator(func):
return deco2(deco1(func))
return real_decorator
This decorator can then be used like this:
@merged_decorator_with_args('bar', 'baz')
def foo():
...