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)
我不确定你的装饰函数试图做什么,因为模也在负整数上工作,但你基本上有两个问题:
- 就像@Anakhand 说你应该return 一个函数而不是函数return 值。
- 你的
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
我正在学习 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)
我不确定你的装饰函数试图做什么,因为模也在负整数上工作,但你基本上有两个问题:
- 就像@Anakhand 说你应该return 一个函数而不是函数return 值。
- 你的
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