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