参数化密码装饰器实现问题:不可修改被装饰函数
问题分析
你的代码存在两个核心错误:
- 逻辑倒置:你试图用原函数的返回值和密码对比,这完全搞反了——应该验证用户传入的密码和装饰器参数是否匹配,而非原函数的输出。
- 参数传递错误:你直接把所有调用参数传给原函数,导致原函数(比如
add)收到多余的密码参数,触发TypeError。
解决方案
我们需要重新设计装饰器逻辑:先从调用参数中提取密码验证,验证通过后,把去除密码后的参数传给原函数。以下提供两种实用实现:
方式一:约定密码为第一个位置参数
适配你示例中add("h",1,2)的调用方式:
def password(pswd): def decorator(f): def wrapper(*args, **kwargs): # 检查是否传入密码 if not args: raise ValueError("Password not provided") # 提取第一个位置参数作为密码 input_pswd = args[0] if input_pswd != pswd: raise ValueError("Invalid password") # 去除密码后,将剩余参数传给原函数 return f(*args[1:], **kwargs) return wrapper return decorator # 使用示例 @password("h") def add(a, b): return a + b # 正确调用 print(add("h", 1, 2)) # 输出3 # 错误调用会抛出ValueError # add("wrong", 1, 2) # add(1, 2)
方式二:约定密码通过关键字参数传入(更灵活)
避免密码和原函数位置参数冲突,推荐使用:
def password(pswd): def decorator(f): def wrapper(*args, **kwargs): # 从关键字参数提取密码,同时移除该参数 input_pswd = kwargs.pop("password", None) if input_pswd is None: raise ValueError("Password not provided") if input_pswd != pswd: raise ValueError("Invalid password") # 传递剩余参数给原函数 return f(*args, **kwargs) return wrapper return decorator # 使用示例 @password("h") def add(a, b): return a + b # 正确调用 print(add(1, 2, password="h")) # 输出3 # 错误调用会抛出ValueError # add(1, 2, password="wrong") # add(1, 2)
进阶:同时支持位置参数和关键字参数
如果需要兼容两种传参方式:
def password(pswd): def decorator(f): def wrapper(*args, **kwargs): input_pswd = None # 优先从关键字参数提取 if "password" in kwargs: input_pswd = kwargs.pop("password") elif args: # 没有关键字参数则取第一个位置参数 input_pswd = args[0] args = args[1:] else: raise ValueError("Password not provided") if input_pswd != pswd: raise ValueError("Invalid password") return f(*args, **kwargs) return wrapper return decorator # 两种调用方式都支持 @password("h") def add(a, b): return a + b print(add("h", 1, 2)) # 输出3 print(add(1, 2, password="h")) # 输出3
内容的提问来源于stack exchange,提问作者Dumbkopf
相关产品推荐
相关产品推荐

