字典拆包核心符号:*、**
*dict:拆出字典的键,多用于序列接收、函数位置参数**dict:拆出键值对,多用于函数关键字传参、字典合并
一、基础概念回顾
字典:d = {"name":"张三", "age":18, "gender":"男"}
d = {"name":"张三", "age":18}
for item in d:
print(item) # name age
** 双星拆包字典 → 拆解成 key=value 形式
一、单星号 * 字典拆包(拆键)
1. 场景1:列表/元组解包、合并序列
d = {"a": 1, "b": 2, "c": 3}
# 把字典所有key拆开放入列表
lst = [*d]
print(lst) # ['a', 'b', 'c']
# 元组
t = (*d,)
print(t) # ('a', 'b', 'c')
# 多个字典合并键集合
d1 = {"x":1, "y":2}
d2 = {"y":99, "z":3}
keys = [*d1, *d2]
print(keys) # ['x', 'y', 'y', 'z']
2. 场景2:函数可变位置参数 *args
函数 *args 接收零散位置参数,字典用 *d 传入会自动拆所有key:
deffunc(*args):
print(args)
d = {"name":"李四", "score":90}
func(*d) # 等价于 func("name", "score")
# 输出:('name', 'score',)
3. 场景3:zip、print 等批量传参
d = {"k1":10, "k2":20}
print(*d) # print("k1", "k2")
# 输出:k1 k2
限制:*d 只能提取键,拿不到值;如果要同时拆键值对,用 d.items():
d = {"a":1, "b":2}
print(*d.items())
# 输出:('a', 1) ('b', 2)
二、双星号 ** 字典拆包(拆键值对,最常用)
**d 会将字典拆解为 key=value 的关键字参数形式,不能单独赋值给变量,只能用在:函数传参、字典合并。
1. 场景1:函数关键字参数传参(高频用法)
示例1:普通函数接收关键字
defuser_info(name, age, gender):
print(f"姓名:{name},年龄:{age},性别:{gender}")
# 原始传参
user_info(name="王五", age=20, gender="男")
# 字典存储参数,**拆包一键传入
user = {"name":"王五", "age":20, "gender":"男"}
user_info(**user)
# 等价于 user_info(name="王五", age=20, gender="男")
示例2:函数可变关键字参数 **kwargs
defshow_data(**kwargs):
print("接收的所有键值对:", kwargs)
data = {"id":1001, "title":"Python教程", "price":29.9}
show_data(**data)
# 输出:接收的所有键值对:{'id': 1001, 'title': 'Python教程', 'price': 29.9}
示例3:混合普通参数、*args、**kwargs
defdemo(a, b, *args, **kwargs):
print(a, b)
print(args)
print(kwargs)
d = {"x":10, "y":20}
demo(1, 2, 3, 4, **d)
# 输出
# 1 2
# (3, 4)
# {'x': 10, 'y': 20}
2. 场景2:字典合并、拷贝(Python3.5+)
方式1:使用 {**d1, **d2} 合并字典
规则:后面字典的同名键会覆盖前面的值
d1 = {"name":"小明", "age":16}
d2 = {"age":17, "gender":"男"}
new_d = {**d1, **d2}
print(new_d)
# {'name': '小明', 'age': 17, 'gender': '男'}
方式2:基于原字典新增/修改字段
student = {"name":"小红", "cls":"一班"}
# 复制原字典,同时新增/覆盖age
new_stu = {**student, "age":15}
print(new_stu)
# {'name': '小红', 'cls': '一班', 'age': 15}
对比 update()
# update 原地修改原字典,会改变原有数据
student.update({"age":15})
# {**d1,**d2} 会生成全新字典,不修改原数据
3. 禁止用法:** 不能单独用于变量赋值
d = {"a":1, "b":2}
x = **d # 直接报错!语法不允许
** 只能出现在 {} 字典字面量、函数调用传参两处。
三、字典 items / keys / values 拆包补充
1. 拆包 items() 键值对
d = {"a": 100, "b": 200}
# 单星拆包 items,得到多个元组
print(*d.items()) # ('a', 100) ('b', 200)
# 循环拆包 k,v
for k, v in d.items():
print(k, v)
2. 拆包 values() 获取所有值
d = {"a":1, "b":2}
val_list = [*d.values()]
print(val_list) # [1, 2]
3. 拆包 keys() 和直接 *d 完全等价
[*d] == [*d.keys()] # True
四、实战综合案例
案例1:接口参数拼接(爬虫/API常用)
base_params = {"appid": "123456", "timestamp": 1780000000}
extra = {"keyword": "python", "page": 1}
# 合并所有请求参数
request_params = {**base_params, **extra}
print(request_params)
# {'appid': '123456', 'timestamp': 1780000000, 'keyword': 'python', 'page': 1}
案例2:类初始化批量传参
classBook:
def__init__(self, name, author, price):
self.name = name
self.author = author
self.price = price
book_info = {"name":"Python入门", "author":"张三", "price":39.8}
# 字典拆包快速实例化
book = Book(**book_info)
print(book.name, book.author) # Python入门 张三
案例3:函数缺省参数 + 字典覆盖
defprint_goods(name, stock=0, price=0):
print(f"{name} 库存:{stock} 价格:{price}")
# 默认参数
print_goods("水杯")
# 用字典覆盖部分默认参数
goods = {"name":"键盘", "price":99}
print_goods(**goods)
# 输出:键盘 库存:0 价格:99
五、单星 * 和双星 ** 字典拆包对比总结
关键记忆点
拓展:Python3.9+ 管道合并字典(|)补充
除 {**d1,**d2} 外,新版本支持 | 合并字典,效果一致:
d1 = {"a":1}
d2 = {"b":2}
new_d = d1 | d2
print(new_d) # {'a': 1, 'b': 2}
但管道运算符无法在函数传参时替代 **,拆包传参仍必须用 **。