Python 从入门到实战(六):字典(关联数据的 “高效管家”)

欢迎回到「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

这种方式有两个大问题:

  1. 查询效率低:列表越长,遍历时间越久;
  2. 可读性差 :看到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元

这里的productprice是 "解包"------ 把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岁
  爱好:阅读, 跑步
  地址:上海

四、综合实操:商品库存管理系统

咱们结合 "字典嵌套 + 循环 + 条件判断",做一个 "商品库存管理系统",实现以下功能:

  1. 用 "字典列表" 存储商品信息(名称、价格、库存);
  2. 遍历商品列表,打印库存清单;
  3. 根据商品名修改库存(比如卖出 5 件苹果,库存减少 5);
  4. 筛选库存不足 50 件的 "缺货商品";
  5. 计算所有商品的总价值(价格 × 库存)。

完整代码:

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"])  # 输出:北京

六、小结与下一篇预告

这篇你学到了什么?

  1. 字典基础 :用{}定义键值对,通过 "键" 访问 / 修改 / 添加 / 删除 "值",用get()避免键错误;
  2. 字典遍历 :遍历键(keys())、遍历值(values())、遍历键值对(items()),用sorted()按顺序遍历;
  3. 字典嵌套:字典列表(多个对象)、列表字典(一个对象的多个同类属性)、字典字典(多个对象的复杂属性);
  4. 实战应用:结合循环和条件判断,实现商品库存管理,高效处理关联数据;
  5. 避坑要点:键必须是不可变类型,避免键重复,嵌套访问要逐层查。

下一篇预告

今天的字典让我们能高效存储关联数据,但当代码越来越长时,重复的逻辑(比如 "计算商品总价值""筛选缺货商品")会导致代码冗余。下一篇咱们会学 Python 的 "代码复用神器"------函数,把重复的逻辑封装成函数,调用时只需一行代码,让程序更简洁、更易维护。

如果这篇内容帮你掌握了字典,欢迎在评论区分享你的 "商品库存管理系统" 改进版本(比如添加 "新增商品" 功能),咱们一起交流进步~

相关推荐
槿花Hibiscus2 小时前
C++基础:session实现和http server类最终组装
服务器·c++·http·muduo
毕设源码-郭学长2 小时前
【开题答辩全过程】以 个性化电影推荐系统为例,包含答辩的问题和答案
java
翔云 OCR API2 小时前
企业工商信息查验API-快速核验企业信息-营业执照文字识别接口
前端·数据库·人工智能·python·mysql
500842 小时前
存量 Flutter 项目鸿蒙化:模块化拆分与插件替换实战
java·人工智能·flutter·华为·ocr
BTU_YC2 小时前
python 内网部署
开发语言·python
ytao_wang2 小时前
pip install -e .报错ModuleNotFoundError: No module named ‘torch‘
pytorch·python·深度学习
Tao____2 小时前
基于若依RuoYi框架开发的物联网平台
java·物联网·mqtt·ruoyi·设备对接
caterpillar2 小时前
Spring Method Agent:一款无侵入的Spring方法级调试神器
java
程序员西西2 小时前
深入探索 Spring Boot3 中 Profiles 多环境配置
java·后端·架构