核心要点
能说清 *args 把多余位置参数收成 tuple、kwargs 把多余关键字参数收成 dict
区分「定义时收集」与「调用时解包」:调用处 *seq 解包序列、dict 解包映射
掌握参数顺序:位置参数 → *args → keyword-only → kwargs
会用 *args/kwargs 透明转发任意签名(装饰器 wrapper、super().init)
标准回答
定义时收集:
def f(a, *args, **kwargs):
# args: (2, 3)
# kwargs: {'x': 1}
f(1, 2, 3, x=1)params = [1, 2]
opts = {'lr': 0.01}
optimizer.step(*params, **opts)- 装饰器 wrapper 转发任意签名:
def wrapper(*args, kwargs): return fn(*args, kwargs) - API 封装兼容未来参数
- 继承时调用
super().__init__(*args, kwargs)仅 keyword 参数:def f(a, *, b, c=1):中b、c必须按名传递。
常见误区
⚠️ 常见踩坑
把「定义时收集」和「调用时解包」搞反:定义 def f(*args) 收集为 tuple,而 f(*lst) 是解包传入;混淆二者会答错。另一个常见错误是参数顺序写反——*args 必须在普通位置参数之后、kwargs 必须在最后,写成 def f( kwargs, *args) 会语法错误。
追问
追问 1:* 单独作为参数是什么意思?
星号后的参数强制 keyword-only(仅关键字传参)。例如 def f(a, *, b) 必须写 f(1, b=2),不能 f(1, 2)。PEP 3102 引入,用于让 API 在增加参数时保持向后兼容,并避免位置参数传错。
追问 2:解包时 dict 的键有什么要求?
d 要求键为 str(Python 3),且与函数形参名一一对应;多出的键会触发 TypeError,除非函数有 kwargs 接收。传参前可用 {k: v for ...} 过滤不需要的键。
追问 3:args 和 kwargs 是固定名字吗?
不是。真正起作用的是 * 和 `` 这两个符号,后面的名字可任取,如 def f(*a, kw) 完全合法。args/kwargs 只是社区约定俗成的命名,用约定名能提升可读性,但不影响语义。
延伸学习
与本题相关的知识库文章、术语、工具与行业资讯。
📰 AI 资讯