Как сделать так, чтобы @decorator и @decorator (args) имели одно и то же имя? - PullRequest
0 голосов
/ 08 января 2019

Я хочу использовать два типа декораторов:

а)

@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

1 Ответ

0 голосов
/ 08 января 2019

Я предполагаю, что предпосылка вопроса ошибочна, поскольку я не много теряю, написав @new() вместо @new, но я получаю последовательность и простоту: новое - это просто декоратор. В качестве альтернативы я мог бы сделать два разных декоратора.

...