
欢迎回到「Python 从入门到实战」系列专栏。上一篇咱们掌握了条件判断,让程序能根据不同情况 "做选择"------ 比如给不同角色的用户分配权限。但在处理 "关联数据" 时,前面学的列表就显得力不从心了:比如要存储 "用户名 - 密码""商品名 - 价格""学生名 - 成绩" 这种 "键 - 值对应" 的信息,用列表得遍历才能找到对应关系(比如找 "张三" 的成绩,要循环整个列表),效率很低。
今天咱们要学 Python 的 "关联数据神器"------字典(Dictionary)。它就像一本 "新华字典":"键" 是 "汉字","值" 是 "拼音和释义",通过 "汉字"(键)能直接找到 "释义"(值),不用逐页翻找(遍历)。学会字典,你就能高效存储和查询结构化数据,为后面的项目(比如用户系统、商品管理)打基础。
一、为什么需要字典?先看列表的 "痛点"
在学字典前,先明确它能解决什么问题。咱们用 "存储用户信息" 这个场景,对比列表和字典的差异:
场景:存储 3 个用户的 "用户名 - 密码"
用列表存储(低效)
如果用列表存,只能把 "用户名" 和 "密码" 分开存两个列表,或者存成 "[用户名,密码]" 的小列表。找某个用户的密码时,必须遍历:
python
运行
python
# 用列表存储用户信息(痛点:找密码要遍历)
users = [["zhangsan", "123456"], ["lisi", "abcdef"], ["wangwu", "654321"]]
# 找"lisi"的密码(需要遍历整个列表)
target_user = "lisi"
target_password = None
for user in users:
if user[0] == target_user:
target_password = user[1]
break
print(f"{target_user}的密码:{target_password}") # 输出:lisi的密码:abcdef
这种方式有两个大问题:
- 查询效率低:列表越长,遍历时间越久;
- 可读性差 :看到
user[0]和user[1],得回忆哪个是用户名、哪个是密码。
用字典存储(高效)
字典用 "键值对" 直接关联数据,找密码不用遍历,直接用 "用户名"(键)查 "密码"(值):
python
运行
python
# 用字典存储用户信息(键:用户名,值:密码)
users = {
"zhangsan": "123456",
"lisi": "abcdef",
"wangwu": "654321"
}
# 找"lisi"的密码(直接用键查,不用遍历)
target_password = users["lisi"]
print(f"lisi的密码:{target_password}") # 输出:lisi的密码:abcdef
对比很明显:字典通过 "键" 直接定位 "值",效率更高;而且users["lisi"]一看就知道是 "找 lisi 的对应值",可读性更好。
这就是字典的核心价值:存储 "键 - 值关联" 的数据,支持高效查询和修改。接下来咱们从基础用法开始,一步步掌握字典的所有核心技能。
二、字典基础:定义与键值对操作
字典在 Python 中用花括号{} 定义,每个元素是 "键:值" 的键值对,键和值之间用冒号分隔,键值对之间用逗号分隔。格式如下:
python
运行
python
字典名 = {
"键1": "值1",
"键2": "值2",
"键3": "值3"
}
- 键(Key):必须是 "不可变类型"(字符串、数字、元组),且不能重复(重复会覆盖);
- 值(Value):可以是任意类型(字符串、数字、列表、甚至字典);
- 键值对:键和值一一对应,一个键只能对应一个值。
1. 定义字典:从简单到复杂
咱们用三个场景演示字典的定义,从 "简单键值对" 到 "值为列表 / 字典":
▶ 场景 1:简单键值对(字符串键 + 字符串值)
存储商品的 "名称 - 价格":
python
运行
python
# 定义商品价格字典(键:商品名,值:价格)
product_prices = {
"苹果": 5.99,
"香蕉": 3.99,
"橙子": 4.5
}
print(product_prices) # 输出:{'苹果': 5.99, '香蕉': 3.99, '橙子': 4.5}
▶ 场景 2:值为列表(一个键对应多个值)
存储用户的 "名称 - 爱好"(一个用户有多个爱好):
python
运行
python
# 定义用户爱好字典(键:用户名,值:爱好列表)
user_hobbies = {
"zhangsan": ["篮球", "编程"],
"lisi": ["阅读", "跑步", "做饭"],
"wangwu": ["游戏", "电影"]
}
print(f"lisi的爱好:{user_hobbies['lisi']}") # 输出:lisi的爱好:['阅读', '跑步', '做饭']
▶ 场景 3:值为字典(复杂结构化数据)
存储用户的 "名称 - 详细信息"(包含年龄、性别、地址):
python
运行
python
# 定义用户详细信息字典(键:用户名,值:信息字典)
user_details = {
"zhangsan": {
"age": 20,
"gender": "male",
"address": "北京"
},
"lisi": {
"age": 22,
"gender": "female",
"address": "上海"
}
}
# 找"zhangsan"的年龄(先查用户字典,再查age键)
print(f"zhangsan的年龄:{user_details['zhangsan']['age']}") # 输出:zhangsan的年龄:20
2. 访问键值对:直接用键查值
访问字典中的值,核心是 "用键找值",语法是字典名[键]。但要注意:如果键不存在,会报KeyError(键错误)。
▶ 基础访问:存在的键
python
运行
python
# 商品价格字典
product_prices = {"苹果": 5.99, "香蕉": 3.99}
# 访问存在的键(苹果)
apple_price = product_prices["苹果"]
print(f"苹果的价格:{apple_price}元") # 输出:苹果的价格:5.99元
▶ 避坑:访问不存在的键(KeyError)
python
运行
python
# 错误示例:访问不存在的键(葡萄)
grape_price = product_prices["葡萄"] # 报错:KeyError: '葡萄'
解决办法 :用get()方法,键不存在时返回默认值(不会报错):
python
运行
python
# 用get()访问,键不存在时返回默认值(0.0)
grape_price = product_prices.get("葡萄", 0.0)
print(f"葡萄的价格:{grape_price}元") # 输出:葡萄的价格:0.0元
# 如果不指定默认值,键不存在时返回None(也不会报错)
orange_price = product_prices.get("橙子")
print(f"橙子的价格:{orange_price}") # 输出:橙子的价格:None
get()方法是新手必须掌握的 "避坑技能",尤其是处理用户输入或动态数据时,能避免因键不存在导致程序崩溃。
3. 修改键值对:更新已有键的值
如果要修改某个键对应的值,直接用字典名[键] = 新值赋值即可,语法和变量赋值类似。
场景:修改商品价格(苹果涨价到 6.99 元)
python
运行
python
# 商品价格字典
product_prices = {"苹果": 5.99, "香蕉": 3.99}
# 修改苹果的价格(键存在,更新值)
product_prices["苹果"] = 6.99
print(f"苹果涨价后的价格:{product_prices['苹果']}元") # 输出:苹果涨价后的价格:6.99元
注意:键不存在时会 "新增" 而非修改
如果赋值的键在字典中不存在,Python 会自动新增一个键值对:
python
运行
python
# 键"葡萄"不存在,赋值会新增键值对
product_prices["葡萄"] = 7.99
print(product_prices) # 输出:{'苹果': 6.99, '香蕉': 3.99, '葡萄': 7.99}
4. 添加键值对:动态扩展字典
字典是 "动态结构",可以随时添加新的键值对,语法和修改一样:字典名[新键] = 新值。
场景:给用户添加 "年龄" 信息
python
运行
python
# 初始用户字典(只有用户名和密码)
user = {"username": "zhangsan", "password": "123456"}
# 添加年龄键值对
user["age"] = 20
# 添加性别键值对
user["gender"] = "male"
print(user) # 输出:{'username': 'zhangsan', 'password': '123456', 'age': 20, 'gender': 'male'}
5. 删除键值对:彻底移除不需要的数据
如果要删除某个键值对,用del 字典名[键]语句,会彻底删除键和对应的值(无法恢复)。
场景:删除用户的 "密码" 键值对(避免泄露)
python
运行
python
# 用户字典(包含敏感信息password)
user = {"username": "zhangsan", "password": "123456", "age": 20}
# 删除password键值对
del user["password"]
print(user) # 输出:{'username': 'zhangsan', 'age': 20}(password已删除)
避坑:删除不存在的键(KeyError)
和访问一样,删除不存在的键会报KeyError,可以先判断键是否存在:
python
运行
python
# 安全删除:先判断键是否存在
if "password" in user:
del user["password"]
else:
print("键'password'不存在,无需删除~")
三、字典进阶:遍历与嵌套
当字典包含多个键值对时,需要 "遍历" 来批量处理;当数据更复杂时(比如多个用户的详细信息),需要 "嵌套"(字典里放列表、列表里放字典)。这两部分是字典的核心应用,必须掌握。
1. 遍历字典:三种常见方式
字典不像列表是 "有序序列"(Python 3.7 + 会保留插入顺序,但遍历逻辑不变),遍历时有三种常见需求:遍历所有键、遍历所有值、遍历所有键值对。
▶ 方式 1:遍历所有键(默认)
如果只需要字典的键,直接用for 键 in 字典遍历(默认遍历键):
python
运行
python
# 商品价格字典
product_prices = {"苹果": 5.99, "香蕉": 3.99, "橙子": 4.5}
# 遍历所有键(默认遍历键)
print("所有商品名称:")
for product in product_prices:
print(f"- {product}")
运行结果:
plaintext
plaintext
所有商品名称:
- 苹果
- 香蕉
- 橙子
也可以用keys()方法显式遍历键(可读性更好):
python
运行
python
for product in product_prices.keys():
print(f"- {product}") # 结果和上面一样
▶ 方式 2:遍历所有值
如果只需要字典的值,用values()方法:
python
运行
python
# 遍历所有值
print("所有商品价格:")
for price in product_prices.values():
print(f"- {price}元")
运行结果:
plaintext
plaintext
所有商品价格:
- 5.99元
- 3.99元
- 4.5元
▶ 方式 3:遍历所有键值对(最常用)
如果需要同时处理键和值,用items()方法,会返回 "(键,值)" 的元组:
python
运行
python
# 遍历所有键值对(同时处理商品名和价格)
print("商品价格表:")
for product, price in product_prices.items():
print(f"{product}:{price}元")
运行结果:
plaintext
plaintext
商品价格表:
苹果:5.99元
香蕉:3.99元
橙子:4.5元
这里的product和price是 "解包"------ 把items()返回的元组(商品名, 价格)拆成两个变量,方便使用。
进阶:按特定顺序遍历键
如果需要按 "字母顺序" 或 "数字顺序" 遍历键,用sorted()函数对键排序:
python
运行
python
# 按字母顺序遍历商品名
print("按字母顺序排列的商品:")
for product in sorted(product_prices.keys()):
print(f"- {product}")
运行结果(按拼音首字母排序):
plaintext
plaintext
按字母顺序排列的商品:
- 苹果
- 橙子
- 香蕉
2. 字典嵌套:三种实用场景
嵌套是处理复杂数据的核心手段,Python 支持 "字典列表""列表字典""字典字典" 三种常见嵌套方式,每种方式对应不同的场景。
▶ 场景 1:字典列表(多个相似对象)
当需要存储 "多个相似结构的对象"(比如多个用户、多个商品)时,用 "列表包含字典" 的结构,每个字典代表一个对象。
示例:存储 3 个商品的详细信息
python
运行
python
# 字典列表:每个元素是商品字典(包含名称、价格、库存)
products = [
{"name": "苹果", "price": 5.99, "stock": 100},
{"name": "香蕉", "price": 3.99, "stock": 200},
{"name": "橙子", "price": 4.5, "stock": 150}
]
# 遍历字典列表,打印商品信息
for product in products:
print(f"商品:{product['name']}")
print(f" 价格:{product['price']}元")
print(f" 库存:{product['stock']}件\n")
运行结果(节选):
plaintext
plaintext
商品:苹果
价格:5.99元
库存:100件
商品:香蕉
价格:3.99元
库存:200件
▶ 场景 2:列表字典(一个对象的多个同类属性)
当需要存储 "一个对象的多个同类属性"(比如一个用户的多个爱好、一个商品的多个标签)时,用 "字典的键对应列表" 的结构。
示例:存储用户的详细信息(包含多个爱好)
python
运行
python
# 列表字典:键对应列表(hobbies是列表,address是字典)
user = {
"username": "zhangsan",
"age": 20,
"hobbies": ["篮球", "编程", "阅读"], # 列表:多个爱好
"address": { # 字典:地址的详细信息
"city": "北京",
"district": "海淀区",
"street": "中关村大街"
}
}
# 访问列表属性(hobbies)
print(f"{user['username']}的爱好:")
for hobby in user["hobbies"]:
print(f"- {hobby}")
# 访问嵌套字典属性(address)
print(f"\n{user['username']}的地址:")
print(f"{user['address']['city']}{user['address']['district']}{user['address']['street']}")
运行结果:
plaintext
plaintext
zhangsan的爱好:
- 篮球
- 编程
- 阅读
zhangsan的地址:
北京海淀区中关村大街
▶ 场景 3:字典字典(多个对象的复杂属性)
当需要存储 "多个对象的复杂属性"(比如多个用户的详细信息,每个用户有地址、爱好)时,用 "字典包含字典" 的结构,外层键是对象标识(比如用户名),内层字典是对象的详细属性。
示例:存储多个用户的详细信息
python
运行
python
# 字典字典:外层键是用户名,内层字典是用户详细信息
users = {
"zhangsan": {
"age": 20,
"hobbies": ["篮球", "编程"],
"address": "北京"
},
"lisi": {
"age": 22,
"hobbies": ["阅读", "跑步"],
"address": "上海"
}
}
# 遍历字典字典,打印每个用户的信息
for username, user_info in users.items():
print(f"\n用户名:{username}")
print(f" 年龄:{user_info['age']}岁")
print(f" 爱好:{', '.join(user_info['hobbies'])}") # 列表转字符串
print(f" 地址:{user_info['address']}")
运行结果(节选):
plaintext
plaintext
用户名:zhangsan
年龄:20岁
爱好:篮球, 编程
地址:北京
用户名:lisi
年龄:22岁
爱好:阅读, 跑步
地址:上海
四、综合实操:商品库存管理系统
咱们结合 "字典嵌套 + 循环 + 条件判断",做一个 "商品库存管理系统",实现以下功能:
- 用 "字典列表" 存储商品信息(名称、价格、库存);
- 遍历商品列表,打印库存清单;
- 根据商品名修改库存(比如卖出 5 件苹果,库存减少 5);
- 筛选库存不足 50 件的 "缺货商品";
- 计算所有商品的总价值(价格 × 库存)。
完整代码:
python
运行
python
# 商品库存管理系统
print("===== 商品库存管理系统 =====")
# 1. 初始化商品列表(字典列表)
products = [
{"name": "苹果", "price": 5.99, "stock": 100},
{"name": "香蕉", "price": 3.99, "stock": 45}, # 库存不足50
{"name": "橙子", "price": 4.5, "stock": 150},
{"name": "葡萄", "price": 7.99, "stock": 30} # 库存不足50
]
# 2. 打印当前库存清单
print("\n【当前库存清单】")
print(f"{'商品名':<8}{'价格(元)':<10}{'库存(件)':<10}")
print("-" * 30)
for product in products:
print(f"{product['name']:<8}{product['price']:<10.2f}{product['stock']:<10}")
# 3. 修改商品库存(比如卖出5件苹果)
target_product = "苹果"
sell_count = 5
for product in products:
if product["name"] == target_product:
if product["stock"] >= sell_count:
product["stock"] -= sell_count
print(f"\n【库存修改】卖出{sell_count}件{target_product},剩余库存:{product['stock']}件")
else:
print(f"\n【库存不足】{target_product}库存只有{product['stock']}件,无法卖出{sell_count}件")
break
else:
print(f"\n【商品不存在】未找到{target_product}")
# 4. 筛选缺货商品(库存<50件)
print("\n【缺货商品清单】(库存<50件)")
shortage_products = [p for p in products if p["stock"] < 50] # 列表推导式
if shortage_products:
for product in shortage_products:
print(f"- {product['name']}:{product['stock']}件")
else:
print("无缺货商品")
# 5. 计算所有商品的总价值
total_value = 0
for product in products:
total_value += product["price"] * product["stock"]
print(f"\n【库存总价值】所有商品总价值:{total_value:.2f}元")
print("\n======================")
运行结果:
plaintext
plaintext
===== 商品库存管理系统 =====
【当前库存清单】
商品名 价格(元) 库存(件)
------------------------------
苹果 5.99 100
香蕉 3.99 45
橙子 4.50 150
葡萄 7.99 30
【库存修改】卖出5件苹果,剩余库存:95件
【缺货商品清单】(库存<50件)
- 香蕉:45件
- 葡萄:30件
【库存总价值】所有商品总价值:1649.15元
======================
这个系统整合了字典的核心用法:用字典列表存储复杂商品信息,用遍历处理所有商品,用条件判断修改库存和筛选缺货商品 ------ 这就是字典在实际项目中的典型应用,比单纯用列表高效得多。
五、新手必踩的 4 个坑:避坑指南
字典的用法灵活,但新手容易在细节上出错,导致逻辑错误或报错。咱们总结 4 个高频坑点:
坑 1:用列表当键(键必须是不可变类型)
字典的键必须是 "不可变类型"(字符串、数字、元组),列表是 "可变类型",不能当键:
python
运行
python
# 错误示例:用列表当键
user = {["zhangsan", "lisi"]: "friends"} # 报错:TypeError: unhashable type: 'list'
原因 :列表可以修改(比如 append 元素),而键需要 "唯一且不可变"。正确做法:用元组当键(如果需要多个值当键):
python
运行
python
# 正确示例:用元组当键
user_pair = ("zhangsan", "lisi")
relationship = {user_pair: "friends"}
print(relationship[user_pair]) # 输出:friends
坑 2:键重复(后定义的会覆盖前定义的)
字典的键不能重复,重复定义会覆盖前面的值:
python
运行
python
# 错误示例:键重复,后值覆盖前值
product_prices = {"苹果": 5.99, "苹果": 6.99}
print(product_prices["苹果"]) # 输出:6.99(5.99被覆盖)
解决办法 :定义前检查键是否存在,或用if 键 not in 字典判断。
坑 3:混淆 "遍历键" 和 "遍历值"
新手容易误以为for x in 字典遍历的是值,实际默认遍历的是键:
python
运行
python
# 错误示例:误以为遍历的是值
product_prices = {"苹果": 5.99, "香蕉": 3.99}
for x in product_prices:
print(x) # 输出:苹果 香蕉(遍历的是键,不是值)
正确做法 :遍历值用for x in product_prices.values()。
坑 4:嵌套访问时漏层(多嵌套要逐层查)
访问嵌套字典时,容易漏层导致报错,比如直接访问user["city"]而不是user["address"]["city"]:
python
运行
python
# 错误示例:嵌套访问漏层
user = {"name": "zhangsan", "address": {"city": "北京"}}
print(user["city"]) # 报错:KeyError: 'city'
# 正确做法:逐层访问
print(user["address"]["city"]) # 输出:北京
六、小结与下一篇预告
这篇你学到了什么?
- 字典基础 :用
{}定义键值对,通过 "键" 访问 / 修改 / 添加 / 删除 "值",用get()避免键错误; - 字典遍历 :遍历键(
keys())、遍历值(values())、遍历键值对(items()),用sorted()按顺序遍历; - 字典嵌套:字典列表(多个对象)、列表字典(一个对象的多个同类属性)、字典字典(多个对象的复杂属性);
- 实战应用:结合循环和条件判断,实现商品库存管理,高效处理关联数据;
- 避坑要点:键必须是不可变类型,避免键重复,嵌套访问要逐层查。
下一篇预告
今天的字典让我们能高效存储关联数据,但当代码越来越长时,重复的逻辑(比如 "计算商品总价值""筛选缺货商品")会导致代码冗余。下一篇咱们会学 Python 的 "代码复用神器"------函数,把重复的逻辑封装成函数,调用时只需一行代码,让程序更简洁、更易维护。
如果这篇内容帮你掌握了字典,欢迎在评论区分享你的 "商品库存管理系统" 改进版本(比如添加 "新增商品" 功能),咱们一起交流进步~