I want to use two type of decorators:
a)
@new
def foo():
print("foo")
b)
@new(arg1, arg2, arg3, ...)
def bar():
print("bar")
Basically, I want to make different handlers for the "new message" event. You should be able to write @message.new
if you'd like to use it for all the messages or @message.new(filter)
if you only want the handler to override the unfiltered handler to process messages from certain people or only the messages that have certain attachments to them.
My first thought was that the decorator could check whether its first argument is a function. If it is, it would guess that it's being used as @message.new
. If the first argument is not a function, it would return a decorator.
from inspect import isfunction
def new(*args):
x = args[0]
if isfunction(x):
return new_noargs(x)
else:
return gen_new_args(args)
def new_noargs(func):
def munc():
print("new_noargs")
func()
return munc
def gen_new_args(args):
def dec(func):
def zunc():
print("new_args:", args)
func()
return zunc
return dec
And it works:
@new
def foo():
print("foo")
@new(1,2,3)
def bar():
print("bar")
It looks very clumsy and unpythonic, though. Is there a more convenient way to solve my problem? Also, if I'd like to use @new(some_function)
, the current new
method would decide that it's being called like this:
@new
def some_function():
...
How can I improve my code?
@overengineer
is a decorator that allows another decorator to be called without brackets. It's still too complicated, but more reusable.
def overengineer(decorator):
def dec(*args):
x = args[0]
if isfunction(x):
return decorator()(x)
else:
return decorator(*args)
return dec
@overengineer
def new(*args):
def dec(func):
def zunc():
print("args:", args)
func()
return zunc
return dec
I guess the premise of the question is flawed as I don't lose much by writing @new()
instead of @new
, but I gain consistency and simplicity: new is just a decorator. Alternatively, I could make two different decorators.