AIGC标识 Python *args 和 **kwargs 到底是啥?7 个误用场景一次说清

系列:Python 底层设计逻辑|类型:排错清单型|分发:CSDN / 博客园 / 腾讯云
字数:约 1500 字

结论先行:*args 把多出来的位置参数收成一个元组,**kwargs 把多出来的关键字参数收成一个字典。它不是"任意参数"的魔法,而是"打包/解包"语法。* 解包可迭代对象,** 解包字典。用错的本质,是没分清"收集"和"展开"两个相反的方向。


1. 最基础的收集:位置参数进元组

def f(a, *args):
    print(a, args)

f(1, 2, 3, 4)              # 1 (2, 3, 4)

要点:args 是普通元组,a 先吃第一个,剩下全进 args。

2. 关键字参数进字典

def g(**kwargs):
    print(kwargs)

g(name="Tom", age=18)       # {'name': 'Tom', 'age': 18}

要点:kwargs 是普通 dict,调用时 k=v 形式都会被收进来。

3. 同时用:顺序铁律 必选 → *args → 默认 → **kwargs

def h(a, *args, b=0, **kwargs):
    ...

反例:def h(a, **kwargs, *args) 直接语法报错——**kwargs 必须放最后。

4. 反向用法:解包传参

def add(x, y, z):
    return x + y + z

nums = (1, 2, 3)
print(add(*nums))           # 6  ← * 把元组拆成位置参数

d = {"x": 1, "y": 2, "z": 3}
print(add(**d))             # 6  ← ** 把字典拆成关键字参数

这是 *args/**kwargs 最高频的实战用法:把"已经装在容器里"的数据喂给函数。

5. 误用 1:用 args 当列表去改

def f(*args):
    args.append(5)          # AttributeError: 'tuple' object has no attribute 'append'

args 是元组,不可变。要改,先 list(args)。

6. 误用 2:字典解包键不匹配

def f(x, y): ...
f(**{"x": 1, "z": 2})       # TypeError: missing required argument 'y'

解包字典的键,必须和形参对得上,多一个少一个都报错。

7. 误用 3:和固定参数重名

def f(x, **kwargs):
    f(x=1, x=2)             # 调用端就语法错:重复关键字

别让 **kwargs 里出现和已有形参同名的键,否则冲突。


对照表:收集 vs 展开

写法 出现位置 作用 得到/消费
*args(def 内) 形参 收集多余位置参数 元组
**kwargs(def 内) 形参 收集多余关键字参数 字典
*seq(调用端) 实参 展开可迭代为位置参数 多个位置参
**dict(调用端) 实参 展开字典为关键字参数 多个关键字参

排错清单(收藏级)

  • 顺序错:记住 位置 → *args → 默认 → **kwargs,** 永远末尾。
  • 想改收集结果:args 是元组,先 list() 再动。
  • 解包字典报错:先核对键名与函数形参 100% 匹配。
  • 装饰器里透传:def wrapper(*args, **kwargs): return fn(*args, **kwargs) 是标准写法,别手写成 fn(args, kwargs)。
  • 只想解包一部分:first, *rest = seq 也能用 * 做赋值解包。

一句话记住:def 里的 */** 是"收口袋",调用端的 */** 是"倒口袋"。方向搞反,就全乱了。

posted @ 2026-10-08 16:15  小小张说故事  阅读(6)  评论(0)    收藏  举报