在Python编程中,单星号(*)与双星号(**)是一对基础却极易混淆的语法符号——它们虽同名“星号”,但一个专门处理可迭代对象,另一个则聚焦于字典操作。许多初学者见到别人代码中的*args和**kwargs时,往往只会简单模仿,一旦遇到实际场景便容易出错。今天我们将彻底拆解这两者的具体用法,让你看完之后能够准确判断该用哪个星号。


一、单星号(*):可迭代对象的“解包利器”与可变位置参数
单星号的核心作用围绕可迭代对象展开——无论是解包列表、元组,还是定义可变数量位置参数,都离不开“可迭代”这一概念。下面介绍的三个高频使用场景,每个都是实际开发中的硬核技能。
1. 用法一:解包可迭代对象,简化赋值与传参
当你持有列表或元组,希望一次性取出内部元素,或者将其整个传递给函数时,单星号能帮你省去大量循环和索引操作。
示例1:解包赋值
# 常规写法:逐个赋值,繁琐
nums = [10, 20, 30, 40]
a = nums[0]; b = nums[1]; c = nums[2]; d = nums[3]
print(a, b, c, d) # 输出:10 20 30 40
# 单星号解包:一步到位
nums = [10, 20, 30, 40]
a, b, c, d = *nums, # 注意末尾的逗号,避免语法报错
print(a, b, c, d) # 输出:10 20 30 40
示例2:解包传递给函数
def add(a, b, c):
return a + b + c
# 常规写法:逐个传
print(add(10, 20, 30)) # 输出:60
# 单星号解包:直接传可迭代对象
nums = [10, 20, 30]
print(add(*nums)) # 等价于 add(10, 20, 30),输出:60
注意:解包时元素个数必须和函数参数个数保持一致,否则会直接触发异常——后续讲解可变参数时会解决这一问题。
2. 用法二:合并多个可迭代对象
单星号还能快速拼接多个列表或元组,比链式调用extend()更加简洁优雅。
list1 = [1, 2, 3]
list2 = [4, 5, 6]
list3 = [7, 8, 9]
# 常规写法:extend 需要多次调用
new_list = list1.copy()
new_list.extend(list2)
new_list.extend(list3)
print(new_list) # [1,2,3,4,5,6,7,8,9]
# 单星号一步到位
new_list = [*list1, *list2, *list3]
print(new_list) # [1,2,3,4,5,6,7,8,9]
3. 用法三:函数的可变位置参数(*args)
这是单星号最核心的用法——当函数不确定接收多少个位置参数时,借助*args将所有传入的位置参数打包为一个元组。参数名不固定(例如*abc也可),但业界惯例推荐使用args。
def add_all(*args):
print("args的类型:", type(args)) #
print("args的内容:", args) # 打包成元组
return sum(args)
print(add_all(10, 20)) # 输出:30
print(add_all(10, 20, 30, 40)) # 输出:100
print(add_all()) # 输出:0(空元组)
请牢记:*args仅能接收位置参数,无法处理关键字参数——例如add_all(a=10, b=20)会直接抛出错误。
二、双星号(**):字典的“专属解包工具”与可变关键字参数
双星号与单星号各司其职——它只作用于字典,用于解包键值对、合并字典,以及定义可变数量关键字参数。同样包含三个高频应用场景。
1. 用法一:解包字典,提取键值对
双星号解包字典时,会将键值对展开,常用于函数参数传递。
def print_info(name, age, city):
print(f"姓名:{name},年龄:{age},城市:{city}")
# 常规传关键字参数
print_info(name="张三", age=25, city="北京")
# 双星号解包字典
info = {"name": "张三", "age": 25, "city": "北京"}
print_info(**info) # 等价于上一行
2. 用法二:合并字典
自 Python 3.5+ 起,使用双星号合并字典比update()更简洁,且不会修改原字典。
dict1 = {"name": "张三", "age": 25}
dict2 = {"city": "北京", "job": "程序员"}
dict3 = {"salary": 15000}
# update 写法会修改原字典
new_dict = dict1.copy()
new_dict.update(dict2)
new_dict.update(dict3)
print(new_dict)
# 双星号一步到位,不修改原字典
new_dict = {**dict1, **dict2, **dict3}
print(new_dict) # 结果同上
注意:若多个字典包含相同键,后面的值会覆盖前面的(与update()行为一致)。
3. 用法三:函数的可变关键字参数(**kwargs)
与*args对应,**kwargs用于接收不确定数量的关键字参数,并将其打包为字典。
def print_kwargs(**kwargs):
print("kwargs的类型:", type(kwargs)) #
print("kwargs的内容:", kwargs)
for key, value in kwargs.items():
print(f"{key}:{value}")
print_kwargs(name="张三", age=25)
print_kwargs(city="北京", job="程序员", salary=15000)
输出分别如下:
kwargs的类型:
kwargs的内容: {'name': '张三', 'age': 25}
name:张三
age:25
kwargs的类型:
kwargs的内容: {'city': '北京', 'job': '程序员', 'salary': 15000}
city:北京
job:程序员
salary:15000
最后送你一个速记口诀,保证再也不会用错:
如果处理的是列表、元组(或任何可迭代对象),需要解包、合并,或者函数需要接收任意数量的位置参数 → 使用单星号(*)
如果处理的是字典,需要解包键值对、合并字典,或者函数需要接收任意数量的关键字参数 → 使用双星号(**)
归根结底,单星号和双星号都是 Python 为了简化代码、提升灵活性而设计的语法糖。只需亲自动手练习几次上述示例,你很快就能形成肌肉记忆,以后再也不会选错。
