当你装饰函数时,你应该返回被装饰的函数本身:
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
func(num)
return is_even_new
而不是调用修饰函数并返回:
def decorate(func):
def is_even_new(*args,**kwargs):
num = abs(*args,**kwargs)
func(num)
return is_even_new()
(注意额外的括号)。在最后一个例子中,当你用@decorate装饰一个函数时,装饰器定义了这个内部函数is_even_new,然后,它不返回后者,而是尝试不带参数地调用它:is_even_new()。这也是为什么你得到 TypeError: abs 期望(确切地)一个论点,但你没有给出它。
请记住,Python 中的函数与其他任何东西(“一等公民”)一样都是对象,因此您可以直接通过它们的名称来引用它们。
另外,作为一个建议,如果你知道用@decorate 装饰的函数只会接受一个参数(如is_even),不要使用变量参数和关键字参数,只需定义装饰函数也只取一个参数:
import functools
def decorate(func):
@functools.wraps(func)
def decorated(x):
func(abs(x))
return decorated
这将使错误消息更有帮助(而不是在 abs 调用时提出,
或者,如果您只想将abs 应用于第一个参数:
def decorate(func):
@functools.wraps(func)
def decorated(x, *args, **kwargs):
func(abs(x), *args, **kwargs)
return decorated
您还会注意到@functools.wraps。这是一个非常有用的标准库实用程序,用于定义包装函数,例如从装饰器返回的那些。它在包装函数上设置特殊属性,如__name__、__module__ 等,使其本质上看起来像被包装的函数。