如何访问传递给Python被装饰函数的args参数中的单个参数fname
问题分析与解决方法
你的实现思路整体正确,问题出在没有从装饰器接收的参数中提取fname变量:fname是被装饰函数的形参,不会自动在wrapper的作用域中生成,需要你手动从传入的位置参数args、关键字参数kwargs中提取对应值。
基础修复方案
因为你所有被装饰函数的第一个参数均为fname,可以直接优先取位置参数的第一个元素,为空时再从关键字参数中查找,适配位置传参和关键字传参两种调用方式:
def mydeco(func): def wrapper(*args, **kwargs): print(args) # 提取fname参数 if args: fname = args[0] else: fname = kwargs.get("fname") if not fname: raise ValueError("被装饰函数必须传入fname参数") try: print('Before func') answer = func(*args,**kwargs) print('after func in wrapper') if answer == 2: print(f"Great job {fname}") except Exception as e: print('blah', e) return wrapper @mydeco def long(fname, lname): print(f"hello {fname} {lname}") return 2 @mydeco def short(fname): print(f"hello {fname}") short('Bob') long('Bob', 'Smith')
运行后可正常输出预期内容:
('Bob',) Before func hello Bob after func in wrapper Great job Bob ('Bob', 'Smith') Before func hello Bob Smith after func in wrapper Great job Bob
进阶兼容方案
如果后续被装饰函数的参数顺序可能调整,fname不一定在第一位,可以用Python标准库inspect模块做参数绑定,不管fname在参数列表的哪个位置都能正确提取:
import inspect def mydeco(func): def wrapper(*args, **kwargs): print(args) # 绑定参数到函数形参,自动匹配位置、关键字参数 sig = inspect.signature(func) bound_args = sig.bind(*args, **kwargs) bound_args.apply_defaults() fname = bound_args.arguments["fname"] try: print('Before func') answer = func(*args,**kwargs) print('after func in wrapper') if answer == 2: print(f"Great job {fname}") except Exception as e: print('blah', e) return wrapper
内容的提问来源于stack exchange,提问作者jouell
相关产品推荐
相关产品推荐

