Python中能否在装饰器内调用被装饰函数?及需求实现问询
问题与解决方案
需求说明
获取用户输入,仅当输入为5时才执行目标函数(如翻倍操作);若用户输入其他数字,装饰器需提示数字不是5并重新请求输入,直到用户输入5为止。
尝试的代码与问题
第一次尝试
代码:
def check_five(func): def wrapper(*args,**kwargs): if args==(5,): return func(*args) else: print("Numbers is not 5.") return func(int(input("Enter a: "))) return wrapper @check_five def double(a): return a+a print(double(int(input("Enter a: "))))
问题:首次输入非5时会提示并重新输入,但第二次输入任意数字都会直接执行目标函数,无法持续验证直到输入5。
第二次尝试
代码:
def check_five(func): def wrapper(*args,**kwargs): if args==(5,): return func(*args) else: print("Numbers is not 5.") return double(int(input("Enter a: "))) return wrapper @check_five def double(a): return a+a print(double(int(input("Enter a: "))))
问题:能正常工作,但装饰器内硬编码了目标函数名double,导致装饰器无法复用在其他函数上,违背了装饰器的设计初衷。
疑问
- 是否存在其他仅使用装饰器就能实现需求的方法?
- Python中能否在装饰器内调用被装饰函数?
解答
关于装饰器内调用被装饰函数
完全可以,这是装饰器的常规用法之一。比如日志装饰器中,会先调用原函数获取返回值,再记录日志。但要注意不能像第二次尝试那样硬编码函数名,应该使用闭包中捕获的func变量(也就是装饰器参数里的原函数引用),这样装饰器才能复用在任意函数上。
正确的实现方式
核心思路是在装饰器的wrapper函数中加入循环逻辑,持续验证输入直到符合条件,再调用原函数:
def check_five(func): def wrapper(*args, **kwargs): # 获取初始传入的参数 num = args[0] if args else kwargs.get('a') # 循环验证,直到输入为5 while num != 5: print("数字不是5。") num = int(input("Enter a: ")) # 符合条件后调用原函数 return func(num) return wrapper @check_five def double(a): return a + a # 测试 print(double(int(input("Enter a: "))))
复用性验证
这个装饰器可以直接复用在其他函数上,比如实现三倍运算:
@check_five def triple(a): return a * 3 # 测试 print(triple(int(input("Enter a: "))))
运行后同样会持续要求输入直到输入5,然后执行三倍运算,说明装饰器的复用性正常。
总结
- 装饰器内调用被装饰函数是合法且推荐的,关键是使用闭包捕获的
func变量,避免硬编码函数名。 - 通过在
wrapper中加入循环逻辑,可以实现持续验证输入直到符合条件的需求,同时保证装饰器的复用性。
内容的提问来源于stack exchange,提问作者Yogesh Rakate
相关产品推荐
相关产品推荐

