python 装饰器不接受函数的参数

python decorator doesn't take the arguments of the function

我正在学习 python,但我被装饰器困住了
我的理解是装饰器向函数添加功能
我做了一个简单的函数来检查一个数字是否是偶数
然后是一个装饰器,它添加了绝对值

def decorate(func):
    def is_even_new(*args,**kwargs):
        num = abs(*args,**kwargs)
        func(num)
    return is_even_new()

@decorate 
def is_even(x):
    if x%2 == 0:
        return True
    else:
        return False

is_even(8)

但我不断收到 TypeError: abs() takes exactly one argument (0 given)
是代码有问题还是我对装饰器的理解是错误的?

修饰函数时,应该return修饰函数本身:

def decorate(func):
    def is_even_new(*args,**kwargs):
        num = abs(*args,**kwargs)
        func(num)

    return is_even_new

而不是 调用 修饰函数并 return 调用:

def decorate(func):
    def is_even_new(*args,**kwargs):
        num = abs(*args,**kwargs)
        func(num)

    return is_even_new()

(注意额外的括号)。在最后一个例子中,当你用 @decorate 装饰一个函数时,装饰器定义了这个内部函数 is_even_new 然后,它尝试不带参数地调用它,而不是 return 后者:is_even_new()。这也是你得到 TypeError 的原因:abs 期望(确切地)一个参数,但你已经给了它 none.

请记住,Python 中的函数与其他任何对象(“first-class citizens”)一样都是对象,因此您可以直接通过名称引用它们。

此外,作为建议,如果您知道用 @decorate 装饰的函数只会接受一个参数(如 is_even),请不要使用可变参数和关键字参数,只需定义 decorate 函数也只接受一个参数:

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。这是一个非常有用的标准库实用程序,用于定义包装函数,例如您 return 从装饰器中定义的包装函数。它在包装函数上设置特殊属性,如 __name____module__ 等,因此它本质上看起来像包装函数。

在您的代码中,您需要以正确的方式 return 来自装饰器的值,并通过牢记其他内部函数的限制将输入数据更改为装饰器,即(绝对采用 1 个位置参数不多),你不能直接从外部调用 return 函数而不像 return is_new_even() 那样提供值,如果想那样做,你也需要在那里传递参数

def decorate(func):
    def is_even_new(val):
        num = abs(val)
        return func(num)
    return is_even_new 

@decorate 
def is_even(x):
    if x%2 == 0:
        return True
    else:
        return False

is_even(8)

我不确定你的装饰函数试图做什么,因为模也在负整数上工作,但你基本上有两个问题:

  1. 就像@Anakhand 说你应该return 一个函数而不是函数return 值。
  2. 你的is_even_new没有return什么

所以我想这是正确的实现:

def decorate(func):
    def is_even_new(*args,**kwargs):
        num = abs(*args,**kwargs)
        return func(num)
    return is_even_new

@decorate
def is_even(x):
    if x%2 == 0:
        return True
    else:
        return False

print(is_even(-8))  # --> True