核心要点

  • 能说清 *args 把多余位置参数收成 tuple、kwargs 把多余关键字参数收成 dict

  • 区分「定义时收集」与「调用时解包」:调用处 *seq 解包序列、dict 解包映射

  • 掌握参数顺序:位置参数 → *args → keyword-only → kwargs

  • 会用 *args/kwargs 透明转发任意签名(装饰器 wrapper、super().init

标准回答

定义时收集

python
def f(a, *args, **kwargs):
    # args: (2, 3)
    # kwargs: {'x': 1}
f(1, 2, 3, x=1)
调用时解包:
python
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):bc 必须按名传递。

常见误区

⚠️ 常见踩坑

把「定义时收集」和「调用时解包」搞反:定义 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 ...} 过滤不需要的键。

追问 3args 和 kwargs 是固定名字吗?

不是。真正起作用的是 * 和 `` 这两个符号,后面的名字可任取,如 def f(*a, kw) 完全合法。args/kwargs 只是社区约定俗成的命名,用约定名能提升可读性,但不影响语义。

延伸学习

与本题相关的知识库文章、术语、工具与行业资讯。