一、为什么需要字典(按名字找值)
列表按顺序存东西,靠位置(第 0 个、第 1 个)找。但生活里很多信息不是靠「排第几」来找的,而是靠名字。
比如查一个同学的手机号,你是想「按名字查」而不是「记住他排第几」。这种「名字 → 值」的对应关系,就是字典。
字典里每一对叫一个键值对:键(key)是名字,值(value)是对应内容。键和值之间用冒号 : 分开,对与对之间用逗号分开,外面用花括号 {} 包住。
phone = {'小明': '138001', '小红': '139002', '小刚': '137003'}
print('小明的手机号:', phone['小明'])
输出:
小明的手机号: 138001
一句人话总结:列表是「第几个」,字典是「叫什么」。
课程思政|数据安全与法治素养 · 能查到,不等于能拿走
字典最擅长把「名字」和「对应的值」配成一对,电话簿、成绩表、库存表都是这个结构。可这一对一对的背后,常常是真实的手机号、成绩、身份证号,属于别人的个人信息。系统里查得到,不代表你就该拿走——做统计、写程序时,只取完成工作必需的那几项,别把整张表顺手存一份。守住这条线,是这一行的底线。
二、创建字典的几种方式
方式一:花括号直接写键值对
person = {'name': '小明', 'age': 19, 'city': '杭州'}
print(person)
输出:
{'name': '小明', 'age': 19, 'city': '杭州'}
方式二:值可以不同类型,甚至嵌套
mixed = {'k1': 100, 'k2': [1, 2, 3], 'k3': {'sub': '值'}}
print(mixed)
输出:
{'k1': 100, 'k2': [1, 2, 3], 'k3': {'sub': '值'}}
方式三:dict() 把「键值对的列表」变成字典
d = dict([('name', '小红'), ('age', 20), ('city', '成都')])
print(d)
输出:
{'name': '小红', 'age': 20, 'city': '成都'}
方式四:用「参数名 = 值」写(键只能是普通名字)
d = dict(name='小刚', age=21, city='西安')
print(d)
输出:
{'name': '小刚', 'age': 21, 'city': '西安'}
方式五:先建空字典,再慢慢填
d = {}
print(d)
d['x'] = 1
print(d)
输出:
{}
{'x': 1}
| 写法 | 适合场景 | 例子 |
|---|---|---|
{'a': 1, 'b': 2} | 已知所有键值对 | 最常用的字面量写法 |
dict([(k, v), ...]) | 数据来自一个列表/元组序列 | 批量导入 |
dict(a=1, b=2) | 键是简单英文单词 | 键不能含空格、中文 |
{} | 先空着,之后用 d[k]=v 填 | 边算边加 |
{}(花括号)。注意它和空集合不一样——集合用 set()。看到花括号里是「名字: 内容」就一定是字典。顺手建一张中国味的排位表
十二生肖的次序是固定的,用「生肖 → 排名」的字典装最合适——想查谁排第几,报名字就行:
rank = {'鼠': 1, '牛': 2, '虎': 3, '兔': 4, '龙': 5, '蛇': 6,
'马': 7, '羊': 8, '猴': 9, '鸡': 10, '狗': 11, '猪': 12}
print(rank['龙'])
print('猴' in rank)
输出:
5
True
键是生肖名,值是排名。想改成「排名 → 生肖」,把两边对调一下就行——这就留给动手试了。
三、取值(d[k] 与 get,KeyError)
想拿某个键对应的值,用方括号写上键名:
books = {'title': 'Python入门', 'author': 'Eric', 'year': 2015}
print(books['title'])
print(books['author'])
输出:
Python入门
Eric
键不存在:直接取下标会报错
用 d['不存在的键'] 会抛 KeyError:
books = {'title': 'Python入门'}
print(books['genre'])
运行后会报错(逐字照抄解释器):
KeyError: 'genre'
更安全的取法:get()
get() 在键不存在时,不会报错,而是返回 None(或者你指定的默认值):
books = {'title': 'Python入门'}
print(books.get('genre'))
print(books.get('genre', '未知类别'))
输出:
None
未知类别
get(键, 默认值)。直接写 d[键] 虽然快,但键一旦不存在就整个程序崩在 KeyError 上。d[k];拿不准在不在,用 d.get(k)。get 的第二个参数是「找不到时返回什么」。课程思政|工匠精神与严谨求实 · 拿不准,就先问一句
取字典里的值,d[键] 写得快,可键一旦不存在,整个程序就崩在 KeyError 上;拿不准在不在,用 d.get(键, 默认值) 才稳。这点小事很能说明态度:面对不确定,是先假设它没问题,还是先留一条稳妥的退路。以后处理真实数据更是如此,缺项、脏值是常态,别赌运气,把「万一没有」提前想到,程序和你自己都更靠得住。
四、添加与修改(d[k]=v、update)
添加:直接给一个新键赋值
car = {'brand': 'Toyota', 'model': 'Corolla'}
car['color'] = 'Blue'
print(car)
输出:
{'brand': 'Toyota', 'model': 'Corolla', 'color': 'Blue'}
修改:键已存在,再赋值就覆盖
car = {'brand': 'Toyota', 'model': 'Corolla'}
car['model'] = 'Camry'
print(car)
输出:
{'brand': 'Toyota', 'model': 'Camry'}
批量更新:update()
一次加或改多个键值对:
car = {'brand': 'Toyota', 'model': 'Corolla'}
car.update({'year': 2020, 'price': 20000})
print(car)
car.update({'model': 'Camry'})
print(car)
输出:
{'brand': 'Toyota', 'model': 'Corolla', 'year': 2020, 'price': 20000}
{'brand': 'Toyota', 'model': 'Camry', 'year': 2020, 'price': 20000}
注意:update 里如果键已经存在,会更新对应的值;不存在才新增。
d[键] = 值」这一个写法就够用了:键不在就是加,键在就是改。要一次加很多,再用 update()。五、删除(del / pop / popitem / clear)
del:按键删掉一对
animals = {'cat': 'mammal', 'bird': 'avian', 'fish': 'aquatic'}
del animals['bird']
print(animals)
输出:
{'cat': 'mammal', 'fish': 'aquatic'}
pop:按键删,还会把「值」还给你
animals = {'cat': 'mammal', 'bird': 'avian', 'fish': 'aquatic'}
val = animals.pop('fish')
print("被删的值:", val)
print(animals)
输出:
被删的值: aquatic
{'cat': 'mammal', 'bird': 'avian'}
popitem:删掉并返回「最后插入」的那一对
animals = {'cat': 'mammal', 'bird': 'avian', 'fish': 'aquatic'}
last = animals.popitem()
print(last)
print(animals)
输出:
('fish', 'aquatic')
{'cat': 'mammal', 'bird': 'avian'}
clear:一键清空
colors = {'red': '#FF0000', 'green': '#00FF00'}
colors.clear()
print(colors)
输出:
{}
| 写法 | 按什么删 | 还能拿回值吗 |
|---|---|---|
del d[键] | 键 | 不能 |
d.pop(键) | 键 | 能,返回被删的值 |
d.popitem() | 最后插入的一对 | 能,返回 (键, 值) |
d.clear() | 全部 | 不能,直接变空 |
pop(键);想清空重来,用 clear()。删不存在的键会报 KeyError,不确定在不在就先用 in 判断。六、遍历三件套(keys / values / items,视图对象、for k in d)
字典有三种「看里面有什么」的方法,常配合 for 使用。
keys():所有键
student = {'name': '小明', 'age': 20, 'major': '计算机'}
print(student.keys())
print(list(student.keys()))
输出:
dict_keys(['name', 'age', 'major'])
['name', 'age', 'major']
values():所有值
prices = {'苹果': 5.5, '香蕉': 3.8, '橙子': 6.0}
print(list(prices.values()))
输出:
[5.5, 3.8, 6.0]
items():所有 (键, 值) 对
staff = {'工号': 101, '姓名': '小美', '部门': '后勤'}
print(list(staff.items()))
输出:
[('工号', 101), ('姓名', '小美'), ('部门', '后勤')]
直接 for 遍历字典,默认拿到的是键
d = {'a': 1, 'b': 2}
for k in d:
print(k)
输出:
a
b
一次性拿到键和值:for k, v in d.items()
d = {'a': 1, 'b': 2}
for k, v in d.items():
print(k, '=>', v)
输出:
a => 1
b => 2
keys()/values()/items() 返回的是「视图对象」,能直接进 for;想看具体长什么样,套个 list() 转成列表即可。七、in 判断的是键不是值
in 用在字典上,判断的是键在不在,不是值在不在:
d = {'name': '小明', 'age': 18}
print('name' in d)
print('小明' in d)
输出:
True
False
'name' in d 是 True(name 是键);'小明' in d 是 False(小明是值,不是键)。
in 会同时查键和值。在字典上它只认键。要判断值在不在这,用 值 in d.values()。d = {'name': '小明', 'age': 18}
print('小明' in d.values())
输出:
True
值 in d.values();想知道「某个键在不在」,直接 键 in d。八、字典的三条规矩(键唯一、键必须不可变、保留插入顺序)
规矩 1:同一个字典里,键不能重复
如果写重复的键,后面的会覆盖前面的,不会报错:
d = {'a': 1, 'a': 2, 'b': 3}
print(d)
输出:
{'a': 2, 'b': 3}
规矩 2:键必须「不可变」(可哈希)
键可以是数字、字符串、元组,但不能是列表、字典这种可变的:
d = {[1, 2]: 3}
运行后会报错(逐字照抄解释器):
TypeError: unhashable type: 'list'
规矩 3:字典保留「插入顺序」
老教材常说「字典无序」,那是以往的说法。较新的 Python 3 版本里,字典会记住你添加键的先后顺序:
d = {'b': 2, 'a': 1, 'c': 3}
print(list(d.keys()))
输出:
['b', 'a', 'c']
输出顺序和写入顺序一致(b、a、c)。所以前面 popitem() 删掉的才是「最后插入」的那一对。
| 规矩 | 说明 | 反例后果 |
|---|---|---|
| 键唯一 | 重复键后者覆盖前者 | 不会报错,但前面的丢了 |
| 键不可变 | 键得是数字/字符串/元组 | 用列表当键报 unhashable |
| 保留插入顺序 | 按添加先后记住顺序 | 老教材说无序,现已过时 |
(x, y) 而不是列表,因为元组不可变、能当键。AI 助手小贴士|「键为什么必须不可变」是字典最值得追问的设计问题。
打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:为什么字典的键必须是不可变类型?用「列表当键会报错」的例子讲清楚背后的 hash 概念,要初中生能听懂
课程思政|诚信与职业操守 · 悄悄被覆盖的,才最危险
字典有条规矩:同一个键写两遍,后面的会把前面的悄悄盖掉,程序一声不吭、照常运行。这在数据里是很可怕的事——两条本该都算的记录,合并时没了一条,结果却看着「正常」。做统计的人最怕这种不报错的丢失,所以合并、汇总前先查重、先对账,比事后解释强。数字不会骗人,但没被发现的覆盖会。
九、嵌套字典(一张学生信息表)
字典的值可以是任何东西,包括另一个字典。这样就能表示「表里有表」的结构,比如一张学生信息表:
students = {
's01': {'name': '小明', 'score': 90, 'city': '北京'},
's02': {'name': '小红', 'score': 85, 'city': '上海'},
}
print(students['s01']['name'])
print(students['s02']['score'])
输出:
小明
85
读取时一层层往下点:students['s01'] 先拿到小明的那本小字典,再 ['name'] 拿到名字。
students = {
's01': {'name': '小明', 'score': 90, 'city': '北京'},
's02': {'name': '小红', 'score': 85, 'city': '上海'},
}
students['s01']['score'] = 95
print(students['s01'])
输出:
{'name': '小明', 'score': 95, 'city': '北京'}
十、字典推导式
列表有列表推导式,字典也有字典推导式:一行就能从别的数据造出一个字典。写法就是把方括号换成花括号,里面写成 键: 值。
{键: 值 for 变量 in 可迭代对象}
{键: 值 for 变量 in 可迭代对象 if 条件}
由浅入深看四种常见用法。
1. 用 range 造一批「数字 → 平方」
print({x: x * x for x in range(1, 6)})
输出:
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
2. 把两个列表「拉链」成一个字典
names = ['小明', '小红', '小刚']
scores = [92, 76, 85]
d = {name: score for name, score in zip(names, scores)}
print(d)
输出:
{'小明': 92, '小红': 76, '小刚': 85}
3. 带条件:只保留想要的
scores = {'小明': 92, '小红': 76, '小刚': 85}
print({k: v for k, v in scores.items() if v >= 85})
输出:
{'小明': 92, '小刚': 85}
4. 把原来的值统一改一改
prices = {'苹果': 5, '香蕉': 3}
print({k: v * 2 for k, v in prices.items()})
输出:
{'苹果': 10, '香蕉': 6}
它和列表推导式的区别只有两点:外面是花括号,里面要写成 键: 值。
| 想要的结果 | 写法 |
|---|---|
| 列表 | [表达式 for 变量 in 数据] |
| 集合 | {表达式 for 变量 in 数据} |
| 字典 | {键: 值 for 变量 in 数据} |
| 带筛选(三种都能加) | 末尾加 if 条件 |
words = ['aa', 'ab', 'ba']
print({w[0]: w for w in words}) # 键 a 出现两次,只剩最后一个
输出:
{'a': 'ab', 'b': 'ba'}
for 循环写一遍,再翻译成推导式。十一、十个基础案例(奶茶菜单、点单统计、播放量排行…)
下面十个例子都很短,建议每个都亲手敲一遍、跑一遍。
1. 奶茶菜单:按名字查价格
menu = {'珍珠奶茶': 12, '芝士葡萄': 18}
print(menu.get('芝士葡萄', '今日售罄'))
输出:
18
2. 口味点单统计:用 get 累加计数
orders = ['珍珠奶茶', '芝士葡萄', '珍珠奶茶', '抹茶拿铁', '芝士葡萄', '珍珠奶茶']
count = {}
for w in orders:
count[w] = count.get(w, 0) + 1
print(count)
输出:
{'珍珠奶茶': 3, '芝士葡萄': 2, '抹茶拿铁': 1}
3. 奶茶均价:求每杯平均价
prices = {'珍珠': 12, '芝士': 18, '抹茶': 15}
vals = list(prices.values())
print('平均每杯:', sum(vals) / len(vals))
输出:
平均每杯: 15.0
4. 改一改订单里的杯数
order = {'奶茶': 1, '炸鸡': 2}
order['奶茶'] = 3
print(order)
输出:
{'奶茶': 3, '炸鸡': 2}
5. 合并两张外卖小票(update)
a = {'奶茶': 12}
b = {'炸鸡': 20}
a.update(b)
print(a)
输出:
{'奶茶': 12, '炸鸡': 20}
6. 从购物车删掉一样并拿回价钱
cart = {'奶茶': 12, '炸鸡': 20}
v = cart.pop('奶茶')
print(v, cart)
输出:
12 {'炸鸡': 20}
7. 找出播放量最高的那首歌
plays = {'起风了': 90, '晴天': 85, '稻香': 78}
best = max(plays, key=plays.get)
print('最多播放:', best, plays[best])
输出:
最多播放: 起风了 90
8. 用 fromkeys 给宿舍每人记 0 次
d = dict.fromkeys(['阿伟', '小美', '老王'], 0)
print(d)
输出:
{'阿伟': 0, '小美': 0, '老王': 0}
9. 判断口味在不在菜单里再取值
d = {'珍珠奶茶': 12}
if '珍珠奶茶' in d:
print('珍珠奶茶 的价格是', d['珍珠奶茶'])
输出:
珍珠奶茶 的价格是 12
10. 嵌套字典里改深层的值
info = {'好友': {'年龄': 18, '城市': '北京'}}
info['好友']['年龄'] = 19
print(info)
输出:
{'好友': {'年龄': 19, '城市': '北京'}}
count.get(w, 0) + 1 实现「有就加一、没有就先记 1」。这个套路背下来,很多计数问题都能套。十二、常见坑(KeyError、列表当键 unhashable、遍历时改字典 RuntimeError、字典不能比大小)
坑 1:用 [] 取不存在的键直接崩
d = {'a': 1}
print(d['b'])
运行后会报错(逐字照抄解释器):
KeyError: 'b'
会抛 KeyError。拿不准在不在,用 d.get('b')(返回 None 也不崩)。
坑 2:用列表当键
d = {[1, 2]: 3}
运行后会报错(逐字照抄解释器):
TypeError: unhashable type: 'list'
列表可变,不能当键,会报 unhashable type: 'list'。换成元组 (1, 2) 就行。
坑 3:遍历字典时删元素
d = {'a': 1, 'b': 2}
for k in d:
del d[k]
运行后会报错(逐字照抄解释器):
RuntimeError: dictionary changed size during iteration
一边遍历一边改字典大小,会报 RuntimeError: dictionary changed size during iteration。正确做法:先收集要删的键,遍历完再删,或遍历 list(d.keys()) 的副本。
坑 4:字典之间不能比大小
print({'a': 1} >= {'a': 1})
运行后会报错(逐字照抄解释器):
TypeError: '>=' not supported between instances of 'dict' and 'dict'
字典只支持 == 和 != 判断相不相等,>、<、>=、<= 都会报 TypeError。两个字典谁「大」没有意义,别写。
坑 5:键重复,前面的被悄悄覆盖
d = {'a': 1, 'a': 2}
print(d)
输出:
{'a': 2}
坑 6:in 判断的是键不是值
d = {'name': '小明'}
print('小明' in d)
print('小明' in d.values())
输出:
False
True
KeyError 先想「是不是键拼错了、或者根本没加进字典」;遇到 unhashable 先想「是不是把列表/字典当键了」。AI 助手小贴士|字典的用法齐了,来几道统计类综合题。
打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:出 3 道字典题:统计一句话里每个字出现的次数、合并两张成绩单、找出平均分最高的学生。等我提交代码再点评
十三、报错手册
下面这些报错都是本机真实运行出来的,照抄解释器原文。
键不存在 KeyError
d = {'a': 1}
print(d['b'])
运行后会报错(逐字照抄解释器):
KeyError: 'b'
原因:字典里没有键 'b'。确定键可能不存在就用 d.get('b')。
列表当键 TypeError(unhashable)
d = {[1, 2]: 3}
运行后会报错(逐字照抄解释器):
TypeError: unhashable type: 'list'
原因:键必须不可变,列表可变,不能哈希。改成元组 {(1, 2): 3}。
遍历时改字典大小 RuntimeError
d = {'a': 1, 'b': 2}
for k in d:
del d[k]
运行后会报错(逐字照抄解释器):
RuntimeError: dictionary changed size during iteration
原因:遍历过程中字典长度变了。先 for k in list(d.keys()): 用副本遍历,再删。
字典比大小 TypeError
print({'a': 1} >= {'a': 1})
运行后会报错(逐字照抄解释器):
TypeError: '>=' not supported between instances of 'dict' and 'dict'
原因:字典只支持相等 == 判断,没有大小关系。删掉 >= 这类比较。
删一个不存在的键 KeyError
d = {'a': 1}
del d['x']
运行后会报错(逐字照抄解释器):
KeyError: 'x'
原因:del / pop 的键不存在。删之前用 if 'x' in d: 判断一下。
字典没有 append 方法 AttributeError
d = {'a': 1}
d.append(('b', 2))
运行后会报错(逐字照抄解释器):
AttributeError: 'dict' object has no attribute 'append'
原因:字典没有 append(那是列表的)。想加键值对用 d['b'] = 2 或 d.update(...)。
KeyError 是键找不到,unhashable 是键类型不对(用了可变对象),changed size during iteration 是遍历时改了字典。先定位「键」在哪一步出了问题。AI 助手小贴士|字典遍历三件套什么时候用哪个,用成绩单场景让 AI 讲,讲完顺便让它出题。
打开任意 AI 对话工具(网页版或 App 都可以),试试这样问:用学生成绩单的例子解释字典的 items()、keys()、values() 各适合什么场合,最后出一道「统计平均分」的遍历练习题
十四、随堂自测(12 题)
点击选项即可判分,选错的题会立刻展开解析。做完可以看到正确率和错题清单,也可以重新答题。
1字典最适合下面哪种使用场景?
- A. 存一串有顺序的数字
- B. 按名字(键)快速查到对应的值
- C. 只存 True / False
- D. 反复做数学运算
2下面哪一行能正确创建一个空字典?
- A.
d = () - B.
d = [] - C.
d = {} - D.
d = ""
{}。() 是空元组,[] 是空列表,"" 是空字符串。3d = {'a': 1},执行 print(d['x']) 会发生什么?
- A. 返回 None
- B. 返回 0
- C. 报 KeyError
- D. 返回空字符串
KeyError: 'x'。想不报错就用 d.get('x'),它返回 None。4d = {'a': 1},执行 print(d.get('x')) 返回什么?
- A. None
- B. 'x'
- C. 报错
- D. 1
get() 在键不存在时返回 None 而不报错。如果写 d.get('x', '缺省'),不存在时就返回你给的默认值。5d = {'a': 1},执行 print(1 in d) 返回什么?
- A. True
- B. False
- C. 报错
- D. 'a'
in 只检查键在不在,1 是值不是键,所以是 False。要判断值在不在要写 1 in d.values()。6d = {'a': 1},执行 d['b'] = 2 之后,d 变成?
- A. 报错
- B.
{'a': 1, 'b': 2} - C.
{'a': 1} - D. 把 'a' 删掉了
d['b'] = 2 给新键 'b' 赋值,字典变成 {'a':1,'b':2}。这个写法「键在就改、键不在就加」,非常常用。7d = {'a': 1, 'b': 2},执行 print(d.pop('a')) 会删掉并返回什么?
- A. 'b'
- B. 2
- C. ('a', 1)
- D. 1
pop(键) 删掉该键并把对应的值返回,所以返回 1,字典剩下 {'b': 2}。要拿「键+值」pair 用 popitem()。8遍历字典 for k in d: 时,循环变量 k 取到的是?
- A. 键
- B. 值
- C. 键值对
- D. 索引序号
for k, v in d.items():;只拿值用 for v in d.values():。9较新的 Python 3 版本里,d = {'b':2, 'a':1, 'c':3} 后 list(d.keys()) 的顺序是?
- A.
['a', 'b', 'c'] - B.
['c', 'b', 'a'] - C.
['b', 'a', 'c'] - D. 随机,每次不一样
['b','a','c']。老的「字典无序」说法已过时。10下面哪个能合法地当作字典的键?
- A.
[1, 2] - B.
{1: 2} - C.
(1, [2, 3]) - D.
(1, 2)
[1,2]、字典、以及含列表的元组 (1,[2,3]) 都不可哈希会报错;(1,2) 是不可变元组,能当键。11{x: x * x for x in range(1, 4)} 的结果是?
- A.
{1: 1, 2: 4, 3: 9} - B.
[1, 4, 9] - C.
{1, 4, 9} - D.
(1, 4, 9)
键: 值,所以得到的是字典。只想要一串值,用列表推导式 [x * x for x in range(1, 4)]。12想从字典 d 里筛出「值大于 60」的键值对,下面哪一句对?
- A.
{k for k, v in d.items() if v > 60} - B.
[k for k in d if v > 60] - C.
{k: v for k in d if v > 60} - D.
{k: v for k, v in d.items() if v > 60}
d.items() 并解包成 k, v,条件写在 if 后面。只写 for k in d 拿不到值 v,会报 NameError。