问题: Python 中 *args 和 **kwargs

👇 点击展开/折叠 面试背诵模板(建议先背这个) `*args` 和 `**kwargs` 是 Python 中用于处理不定长参数的语法。`*args` 接收任意数量的位置参数,打包为元组(tuple);`**kwargs` 接收任意数量的关键字参数,打包为字典(dict)。名称 `args` 和 `kwargs` 是约定俗成的命名,核心在于 `*` 和 `**` 操作符。它们常用于装饰器、子类继承中传递不确定参数,以及函数参数数量不确定的场景。使用时需注意顺序:普通参数 → `*args` → 默认参数 → `**kwargs`。`*` 和 `**` 也可用于解包序列和字典作为函数实参。
---

基础用法示例

1
2
3
4
5
6
7
8
9
10
def demo(a, b, *args, **kwargs):
print(f"a={a}, b={b}")
print(f"args={args}") # 元组
print(f"kwargs={kwargs}") # 字典

demo(1, 2, 3, 4, 5, name="张三", age=18)
# 输出:
# a=1, b=2
# args=(3, 4, 5)
# kwargs={'name': '张三', 'age': 18}

参数定义的顺序规则

函数参数必须按以下顺序定义,否则会报语法错误:

  1. 普通位置参数(必填)
  2. ***args**(收集多余位置参数)
  3. 默认参数(有默认值的参数)
  4. ****kwargs**(收集多余关键字参数)
1
2
3
4
5
6
def correct_order(pos1, pos2, *args, default="默认", **kwargs):
pass
# ✅ 正确

def wrong_order(pos1, default="默认", *args): # ❌ 默认参数不能出现在 *args 前
pass

打包(定义时) vs 解包(调用时)

场景 符号 作用 示例
定义函数(打包) *args 将多余位置参数打包为元组 def f(*args):
定义函数(打包) **kwargs 将多余关键字参数打包为字典 def f(**kwargs):
调用函数(解包) *list 将列表/元组拆解为位置参数 f(*[1,2,3])
调用函数(解包) **dict 将字典拆解为关键字参数 f(**{'a':1, 'b':2})
1
2
3
4
5
6
7
8
9
# 解包示例:调用时展开序列和字典
def add(a, b, c):
return a + b + c

nums = [1, 2, 3]
print(add(*nums)) # 6(等价于 add(1,2,3))

info = {'a': 1, 'b': 2, 'c': 3}
print(add(**info)) # 6(等价于 add(a=1,b=2,c=3))

典型应用场景

  • 装饰器:将 *args, **kwargs 传递给被装饰函数,确保通用性。
  • 子类初始化:调用 super().__init__(*args, **kwargs) 时,将父类不关心的参数传递下去。
  • API 封装:编写通用请求函数时,将额外参数通过 **kwargs 转发到底层库。
  • 参数收集:不确定用户会传入多少个参数时(如求和函数)。
1
2
3
4
5
6
# 装饰器场景
def logger(func):
def wrapper(*args, **kwargs):
print(f"调用 {func.__name__}")
return func(*args, **kwargs) # 原样转发
return wrapper

常见陷阱与注意点

  • *args 名字可任意命名,关键在于 * 前缀,如 *params 也合法,但遵循约定不用。
  • **kwargs 若未传入任何关键字参数,kwargs 为空字典 {};*args 同理为空元组 ()。
  • **不能同时使用两个 *args 或两个 **kwargs**,会引发语法错误。
  • 解包时字典键名必须与函数参数名匹配,否则抛出 TypeError。
  • 在函数调用中使用 * 解包时,若列表长度与函数形参数量不一致,会报错。