Python装饰器中*args和**kwargs传递的疑问求证
问题
我想彻底搞明白:为什么装饰器的wrapper函数用*args和**kwargs做参数后,调用原函数时必须用*args和**kwargs,不能用其他参数替代?
我的初步思路是:*args和**kwargs在wrapper里会被接收成元组和字典,就算原函数不需要参数,也会传入空元组和空字典;如果调用原函数时用*args和**kwargs,会把空的元组和字典解包,不会报错。想确认这个假设对不对。
第一段代码示例
def decorator_function(original_function): def wrapper_function(*args,**kwargs): print('this print statement is the added functionality of this decorator function') original_function(args,kwargs) return wrapper_function @decorator_function def display(): print('display ran') @decorator_function def display_info(name,age): print(f"display function ran with {name, age}") display_info('foo',100) display()
第二段代码示例
def decorator_function(original_function): def wrapper_function(*args,**kwargs): print('this print statement is the added functionality of this decorator function') original_function(*args,**kwargs) return wrapper_function @decorator_function def display(): print('display ran') @decorator_function def display_info(name,age): print(f"display function ran with {name} and {age}") display_info('foo',100) display()
解答
你的假设完全正确,核心逻辑在于Python的参数打包与解包机制:
当
wrapper函数定义为wrapper_function(*args, **kwargs)时,所有传入装饰后函数的位置参数会被打包成元组存入args,关键字参数会被打包成字典存入kwargs。哪怕没有传任何参数,args就是空元组(),kwargs就是空字典{}。如果调用原函数时直接写
original_function(args, kwargs),相当于把整个元组和字典作为两个独立的位置参数传给原函数:- 调用
display_info('foo',100)时,args是('foo',100),kwargs是{},原函数预期接收name和age两个参数,但实际会把name赋值为('foo',100),age赋值为{},完全不符合业务逻辑; - 调用无参的
display()时,相当于给原函数传了两个参数(空元组和空字典),直接触发TypeError: display() takes 0 positional arguments but 2 were given错误。
- 调用
而使用
original_function(*args, **kwargs)时,*会将args元组中的元素逐个拆分为位置参数,**会将kwargs字典中的键值对拆分为关键字参数:- 调用
display_info('foo',100)时,*args会把('foo',100)拆成'foo'和100两个位置参数,完美匹配原函数的参数要求; - 调用
display()时,*args解包空元组(等价于不传位置参数),**kwargs解包空字典(等价于不传关键字参数),完全符合原函数无参的定义,不会触发任何错误。
- 调用
内容的提问来源于stack exchange,提问作者gix
相关产品推荐
相关产品推荐

