一、什么是可变参数
正常函数定义时,形参数量固定,调用时必须传入对应个数实参;可变参数允许函数接收任意数量的实参,分为两类:
- 位置可变参数:
*args 接收任意个位置参数,打包成元组 - 关键字可变参数:
**kwargs 接收任意个关键字参数,打包成字典
二、*args 位置可变参数
1. 基础语法
def 函数名(*args):
# args 是元组 tuple,存放所有多余位置参数
pass
- args 只是约定变量名,可换成
*nums、*data,规范用 args
2. 基础示例:求和任意数字
defsum_all(*args):
print("args类型:", type(args))
print("args内容:", args)
total = 0
for num in args:
total += num
return total
print(sum_all()) # 无参数:() → 0
print(sum_all(1, 2)) # (1,2) → 3
print(sum_all(1, 2, 3, 4, 5)) # (1,2,3,4,5) → 15
输出:
args类型: <class 'tuple'>
args内容: ()
0
args类型: <class 'tuple'>
args内容: (1, 2)
3
args类型: <class 'tuple'>
args内容: (1, 2, 3, 4, 5)
15
3. 固定参数 + *args 混合
规则:普通位置参数必须写在 *args 前面
defshow(name, *args):
print(f"姓名:{name}")
print("其他参数:", args)
show("小明", 18, "男", "西安")
# 姓名:小明
# 其他参数:(18, '男', '西安')
错误写法(args在前会报错):
# 报错:语法不允许
defshow(*args, name):
pass
4. 解包:列表/元组传入 *args
调用函数时,* 可以将列表、元组拆分成独立位置参数
defcalc(*args):
return sum(args)
lst = [10, 20, 30]
tup = (1, 2)
print(calc(*lst)) # 等价 calc(10,20,30) → 60
print(calc(*tup)) # 等价 calc(1,2) → 3
三、**kwargs 关键字可变参数
1. 基础语法
def 函数名(**kwargs):
# kwargs 是字典 dict,存放所有多余关键字参数
pass
** 作用:把多个 key=value 关键字参数打包成字典
2. 基础示例:打印用户信息
defuser_info(**kwargs):
print("kwargs类型:", type(kwargs))
print("字典内容:", kwargs)
for k, v in kwargs.items():
print(f"{k}: {v}")
user_info(name="小红", age=20, city="北京")
输出:
kwargs类型: <class 'dict'>
字典内容: {'name': '小红', 'age': 20, 'city': '北京'}
name: 小红
age: 20
city: 北京
3. 固定关键字参数 + **kwargs 混合
规则:**kwargs 必须放在所有参数最后
defuser(name, age, **kwargs):
print(f"固定:{name}, {age}")
print("额外信息:", kwargs)
user("小李", 22, gender="男", height=175)
# 固定:小李, 22
# 额外信息: {'gender': '男', 'height': 175}
4. 字典解包传入 **kwargs
调用时 ** 将字典拆分为 key=value 关键字参数
defprint_info(**kwargs):
print(kwargs)
info = {"name": "小张", "score": 90}
print_info(**info) # 等价 print_info(name="小张", score=90)
# {'name': '小张', 'score': 90}
四、四种参数混合完整顺序(重中之重)
函数形参书写强制固定顺序,顺序错直接语法报错:位置参数 → 默认参数 → *args → 命名关键字参数 → **kwargs
完整模板:
deffunc(pos1, pos2, d1=10, d2=20, *args, nkw, nkw2=0, **kwargs):
pass
完整混合示例
deffull_func(a, b, c=100, *args, flag, end=999, **kwargs):
print("1. 固定位置:", a, b)
print("2. 默认参数:", c)
print("3. *args元组:", args)
print("4. 命名关键字flag:", flag)
print("5. 命名关键字默认end:", end)
print("6. **kwargs字典:", kwargs)
# 调用
full_func(1, 2, 3, 4, 5, flag=True, x=1000, y=2000)
输出:
1. 固定位置: 1 2
2. 默认参数: 3
3. *args元组: (4, 5)
4. 命名关键字flag: True
5. 命名关键字默认end: 999
6. **kwargs字典: {'x': 1000, 'y': 2000}
关键规则总结
*args 只能出现在默认参数后、**kwargs 前*args 和 **kwargs 可以单独使用,也可以同时存在- 命名关键字参数必须放在
*args 和 **kwargs 中间
五、*args 与 **kwargs 组合使用(万能传参)
同时定义 *args, **kwargs 的函数,可以接收任意类型、任意数量参数,是通用封装常用写法。
defuniversal_func(*args, **kwargs):
print("位置参数元组:", args)
print("关键字参数字典:", kwargs)
universal_func(1, 2, "test", name="老王", tel=123456)
输出:
位置参数元组: (1, 2, 'test')
关键字参数字典: {'name': '老王', 'tel': 123456}
实用场景:函数转发(装饰器/代理函数)
把收到的所有参数原封不动传给内部函数:
defwrapper(*args, **kwargs):
print("转发前日志")
target_func(*args, **kwargs)
deftarget_func(a, b, msg="ok"):
print(a + b, msg)
wrapper(10, 20, msg="完成")
# 转发前日志
# 30 完成
六、易错点与避坑指南
坑1:顺序写错直接报错
# 错误:*args 在普通参数前
defbad(*args, name):
pass
# 错误:**kwargs 不在最后
defbad2(**kwargs, *args):
pass
坑2:默认参数与 *args 混用传参歧义
deftest(a=10, *args):
print(a, args)
test(100, 200, 300)
# a=100,args=(200,300),不会触发默认值
坑3:解包符号 * / ** 只能在定义形参、函数调用时使用
不能在普通变量赋值随便用:
lst = [1,2,3]
x = *lst # 语法错误
坑4:可变参数内部是独立容器,互不干扰
args是元组(不可修改),kwargs是字典(可增删键值)
defdemo(*args, **kwargs):
kwargs["new"] = 123# 字典可修改
# args.append(99) # 报错,元组不能修改
七、高级拓展:仅 * 分隔参数
单独写 * 不接收参数,作用:强制后续参数必须用关键字传递,限制调用方式:
deflimit_func(a, b, *, c, d=0):
print(a, b, c, d)
limit_func(1, 2, c=3) # 正确,c必须关键字传参
limit_func(1, 2, 3) # 报错,c不能用位置传入
八、完整实战案例:计算器封装
支持任意数字加减乘,额外配置通过关键字传入
defcalculator(op, *nums, **config):
if op == "add":
res = sum(nums)
elif op == "mul":
res = 1
for i in nums:
res *= i
else:
res = None
# 读取配置参数
precision = config.get("precision", 2)
return round(res, precision)
print(calculator("add", 1, 2, 3, 4, precision=1)) # 10.0
print(calculator("mul", 2, 3, 5)) # 30
九、核心知识点速记
*args:收集位置参数 → 元组;调用时 *列表/元组 解包**kwargs:收集关键字参数 → 字典;调用时 **字典 解包- 参数顺序:普通参数 > 默认参数 >
*args > 命名关键字 > **kwargs *args, **kwargs 组合实现万能参数接收,常用于装饰器、工具封装