内容提要
大部分新的Python程序员需要时间理解 *args 和 **kwargs 这两个魔法变量。*args 在函数定义时使用,允许传入无穷多个参数。**kwargs 允许传入不定长度的键值对参数。可以使用 *args 和 **kwargs 调用函数,并在装饰器中使用它们。
延伸解读
参数顺序的硬性规则
文章明确指出,当函数同时使用普通位置参数、*args 和 **kwargs 时,定义顺序必须是 some_func(fargs, *args, **kwargs)。这个顺序不是风格建议,而是 Python 语法要求:位置参数在前,*args 收集中间的位置参数,**kwargs 最后收集关键字参数。如果顺序写错,解释器会直接报错,因此初学时最好把这个顺序当作固定模板来记忆。
装饰器兼容性的关键
文章用计时装饰器的例子说明,如果装饰器内部只写固定参数(如 def wrap(a)),那么被装饰函数一旦有两个或更多参数就会报错。把装饰器改为 def wrap(*args, **kwargs),并在内部用 func(*args, **kwargs) 调用原函数,就能兼容任意参数形式。这解释了为什么 *args 和 **kwargs 在装饰器场景中几乎是标配。
猴子补丁的简单示例
文章提到 *args 和 **kwargs 也可用于猴子补丁,即在运行时修改类的方法。示例中把 someclass.get_info 替换为一个返回测试数据的函数,该函数用 *args 接收原方法可能传入的参数。这样可以在不改变调用方式的前提下替换实现,常用于测试时把真实 API 调用换成模拟数据。
Q&A
*args 和 **kwargs 在 Python 函数定义中分别有什么作用?
*args 用于接收任意数量的位置参数,**kwargs 用于接收不定长度的键值对参数。
为什么 Python 中通常写成 *args 和 **kwargs,而不是其他名字?
只有前面的星号是必须的,名字可以自定义,*args 和 **kwargs 只是约定俗成的命名。
在函数中同时使用普通参数、*args 和 **kwargs 时,顺序应该是怎样的?
顺序为:位置参数、*args、**kwargs,例如 some_func(fargs, *args, **kwargs)。
如何使用 *args 和 **kwargs 来调用一个已有函数?
可以用 *args 传递位置参数元组,用 **kwargs 传递关键字参数字典,例如 test_args_kwargs(*args) 或 test_args_kwargs(**kwargs)。
*args 和 **kwargs 最常见的应用场景是什么?
最常见的用例是在编写函数装饰器时,装饰器可以使用 *args 和 **kwargs 来处理不同数量的参数。
在装饰器中如何使用 *args 和 **kwargs 来支持任意参数的函数?
在装饰器的内层函数中定义 def wrap(*args, **kwargs),然后调用 func(*args, **kwargs),这样无论被装饰函数有多少参数都能兼容。