*args — 收集任意数量的位置参数到一个元组中。
**kwargs — 收集任意数量的命名参数(键=值)到一个字典中。
这使得可以编写具有灵活接口的函数:
def my_func(a, b, *args, **kwargs): print(a, b) print(args) print(kwargs) my_func(1, 2, 3, 4, x=10, y=20) # 1 2 # (3, 4) # {'x': 10, 'y': 20}
细节:
可以交换 *args 和具有默认值的命名参数的顺序吗,例如:
def foo(a, *args, x=10, **kwargs): pass
或者默认值是否必须总是在 *args 之后?
答案:
在 Python 3 中可以!像这样(在 Python 2 中不工作):
def foo(a, *args, x=10): pass
*args 后面的参数("仅限关键字参数")可以具有默认值或是必需的 — 只能通过名称指定。
故事
通过 *args/**kwargs 传递错误的参数
在 REST API 服务中,数据编组的自动化是通过 **kwargs 完成的。多余的参数没有被注意到 — 函数在 kwargs 中接受了意外的值,导致控制逻辑丢失,并出现难以调试的错误。
故事
命名参数重复
在调用函数时,开发者意外地既通过显式参数又通过 **kwargs 指定了参数,例如:my_func(a=1, **{"a": 2})。结果是 — TypeError 和服务崩溃。
故事
忘记了位置参数或仅命名的参数
在编写装饰器时,不正确的参数传递(未遵循顺序和结构)导致原始函数接收到的参数数量不正确,协议发生变化,因此在生产中开始出现 TypeError 调用错误。