Я хочу использовать два типа декораторов:
а)
@new
def foo():
print("foo")
б)
@new(arg1, arg2, arg3, ...)
def bar():
print("bar")
По сути, я хочу сделать разные обработчики для события "новое сообщение". Вы должны иметь возможность написать @message.new
, если вы хотите использовать его для всех сообщений, или @message.new(filter)
, если вы хотите, чтобы обработчик переопределял нефильтрованный обработчик для обработки сообщения от определенных людей или только сообщения, которые имеют определенные вложения к ним.
Моей первой мыслью было, что декоратор может проверить, является ли его первый аргумент функцией. Если это так, он бы предположил, что он используется как @message.new
Если первый аргумент не является функцией, он возвращает декоратор.
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
И это работает:
@new
def foo():
print("foo")
@new(1,2,3)
def bar():
print("bar")
Хотя это выглядит очень неуклюже и не пифонично Есть ли более удобный способ решить мою проблему? Кроме того, если бы я хотел использовать @new(some_function)
, текущий метод new
решил бы, что он вызывается так:
@new
def some_function():
...
Как я могу улучшить свой код?
Обход
@overengineer
- это декоратор, который позволяет вызывать другой декоратор без скобок. Это все еще слишком сложно, но многократно.
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