I\'d like to create a Python decorator that can be used either with parameters:
@redirect_output(\"somewhere.log\")
def foo():
....
or
Several answers here already address your problem nicely. With respect to style, however, I prefer solving this decorator predicament using functools.partial
, as suggested in David Beazley's Python Cookbook 3:
from functools import partial, wraps
def decorator(func=None, foo='spam'):
if func is None:
return partial(decorator, foo=foo)
@wraps(func)
def wrapper(*args, **kwargs):
# do something with `func` and `foo`, if you're so inclined
pass
return wrapper
While yes, you can just do
@decorator()
def f(*args, **kwargs):
pass
without funky workarounds, I find it strange looking, and I like having the option of simply decorating with @decorator
.
As for the secondary mission objective, redirecting a function's output is addressed in this Stack Overflow post.
If you want to dive deeper, check out Chapter 9 (Metaprogramming) in Python Cookbook 3, which is freely available to be read online.
Some of that material is live demoed (plus more!) in Beazley's awesome YouTube video Python 3 Metaprogramming.
Happy coding :)