简体   繁体   中英

How can I make @decorator and @decorator(args) share the same name?

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?

Workaround

@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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM