如何使@decorator和@decorator(args)具有相同的名称?

时间:2019-01-08 15:45:55

标签: python python-3.x python-decorators

我想使用两种类型的装饰器:

a)

@new
def foo():
    print("foo")

b)

@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 :(得分:0)

我想这个问题的前提是有缺陷的,因为我写@new()而不是@new并不会造成很多损失,但是我获得了一致性和简单性:new只是一个装饰器。另外,我可以制作两个不同的装饰器。