10  字典dict

10.1 字典的创建

字典(dictionary)是一组键/值对(key/value pair)的数据结构。 每个键对应于一个值,根据键可以查询到值。

字典的键必须可哈希(详见 章节 22 ),因此键不能是列表、集合等可变类型。 字典的键不能重复。字典的值可以是任意对象。

创建字典有 3 种方式:字面量、dict() 类、字典推导式。

# 字典字面量,存储了大圣的资料
wukong = {
    'name': '孙悟空',
    'sex': '男',
    'weapon': ['如意金箍棒'],
    'skill': ['七十二变', '筋斗云']
}
print(wukong)
{'name': '孙悟空', 'sex': '男', 'weapon': ['如意金箍棒'], 'skill': ['七十二变', '筋斗云']}

10.1.1 字典字面量

字典字面量用花括号 {} 包围,键和值之间用冒号 : 分隔,键值对之间用逗号 , 分隔。

# 空字典
d = {}
print(type(d))
<class 'dict'>
注记注意:{} 不是空集合

{} 是空字典。空集合要用 set()

print(type({}))
<class 'dict'>

10.1.2 dict() 类

dict() 类可以接受多种形式的参数来创建字典:

# 无参数 → 空字典
d1 = dict()
print(d1)

# 用字典创建字典
d2 = dict({1: 'food', 2: 'drink'})
print(d2)

# 用关键字参数(键自动成为字符串)
d3 = dict(baidu='baidu.com', google='google.com')
print(d3)

# 用可迭代对象(每个元素是长度为 2 的可迭代对象)
d4 = dict([('id', '1001'), ('name', 'Jenny')])
print(d4)
{}
{1: 'food', 2: 'drink'}
{'baidu': 'baidu.com', 'google': 'google.com'}
{'id': '1001', 'name': 'Jenny'}

10.1.3 字典推导式

字典推导式与列表推导式类似,但使用 {} 包围,且表达式部分是 key: value 形式:

# 将字典的键值互换
d1 = {1: 'food', 2: 'drink', 3: 'fruit'}
d2 = {value: key for key, value in d1.items()}
print(d2)
{'food': 1, 'drink': 2, 'fruit': 3}
# 生成平方表(只保留偶数的平方)
{x: x * x for x in range(6) if x % 2 == 0}
{0: 0, 2: 4, 4: 16}
注记例:字典推导式中的嵌套循环
{key: value for key in 'ABC' for value in range(3)}
{'A': 2, 'B': 2, 'C': 2}

for 子句的执行顺序与嵌套 for 循环相同——外层循环 for key in 'ABC',内层循环 for value in range(3),因此每个 key 对应 3 个值,后面的值覆盖前面的值,最终只保留最后的值。

10.2 字典遍历

10.2.1 字典视图

字典视图有 3 种:keys()values()items(),分别查看键、值、键值对。它们都是可迭代对象,可用于 for 循环。

d = {1: 'food', 2: 'drink', 3: 'fruit'}

print(d.keys())
print(d.values())
print(d.items())
dict_keys([1, 2, 3])
dict_values(['food', 'drink', 'fruit'])
dict_items([(1, 'food'), (2, 'drink'), (3, 'fruit')])
d = {1: 'food', 2: 'drink', 3: 'fruit'}

for k in d.keys():
    print(k, end=' ')

print()

for v in d.values():
    print(v, end=' ')

print()

for item in d.items():
    print(item, end=' ')
1 2 3 
food drink fruit 
(1, 'food') (2, 'drink') (3, 'fruit') 

10.2.2 遍历字典

d = {1: 'food', 2: 'drink', 3: 'fruit'}

# 方式一:直接遍历字典(遍历的是键)
for k in d:
    print(f'键={k}, 值={d[k]}', end='  ')

print()

# 方式二:遍历 items()(推荐)
for k, v in d.items():
    print(f'键={k}, 值={v}', end='  ')
键=1, 值=food  键=2, 值=drink  键=3, 值=fruit  
键=1, 值=food  键=2, 值=drink  键=3, 值=fruit  

CPython 3.6 起,字典的元素保持插入顺序。

10.3 字典操作与方法

10.3.1 通过键访问、修改、删除

字典是可变对象。通过键可以查看、修改、添加、删除键值对。

d = {1: 'food', 2: 'drink', 3: 'fruit'}

# 通过键访问值
print(d[1])

# 通过键修改值
d[1] = 'rice'
print(d)

# 添加新键值对
d[4] = 'snack'
print(d)

# 删除键值对
del d[2]
print(d)
food
{1: 'rice', 2: 'drink', 3: 'fruit'}
{1: 'rice', 2: 'drink', 3: 'fruit', 4: 'snack'}
{1: 'rice', 3: 'fruit', 4: 'snack'}
# 访问不存在的键会报错
d[5]
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
Cell In[12], line 2
      1 # 访问不存在的键会报错
----> 2 d[5]

KeyError: 5

10.3.2 成员判断、长度、比较

d = dict(a='apple', b='boy', c='cat', d='dog')

print('a' in d)
print('e' not in d)
True
True
d1 = {1: 'food', 2: 'drink'}
d2 = {1: 'food', 2: 'drink', 3: 'fruit'}
d3 = {1: 'food', 2: 'drink', 3: 'fruit'}

print(len(d1))
print(d1 == d2)
print(d2 == d3)
2
False
True

10.3.3 常用方法

方法 功能 键不存在时
d.get(k) 返回键 k 对应的值 返回 None(不报错)
d.get(k, v) 返回键 k 对应的值 返回 v
d.setdefault(k, v) 返回键 k 对应的值 添加键值对 k=v 并返回 v
d.pop(k) 删除键 k 并返回其值 报错
d.pop(k, v) 删除键 k 并返回其值 返回 v
d.popitem() 删除并返回最后添加的键值对 报错
d.update(x) 用 x 中的键值对更新字典
d.clear() 清空字典
d = {'a': 1, 'b': 2, 'c': 3}

# get 与 setdefault
print(d.get('a'))
print(d.get('x'))          # None,不报错
print(d.get('x', 0))       # 指定默认值
1
None
0
# setdefault:键不存在时设置默认值
d = {'a': 1}
d.setdefault('b', 2)
print(d)
d.setdefault('a', 99)  # 键已存在,不改变
print(d)
2
{'a': 1, 'b': 2}
1
{'a': 1, 'b': 2}
# pop 与 popitem
d = {'a': 1, 'b': 2, 'c': 3}
print(d.pop('b'))
print(d)
print(d.popitem())  # 删除并返回最后添加的
print(d)
2
{'a': 1, 'c': 3}
('c', 3)
{'a': 1}
注记例:用 get() 简化计数代码
# 统计列表中各元素出现次数
items = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
count = {}
for item in items:
    count[item] = count.get(item, 0) + 1
print(count)
{'apple': 3, 'banana': 2, 'orange': 1}
注记例:对字典排序

sorted() 可以对字典视图排序,结合 lambda 函数可按值或按键排序。

d1 = {'apple': 5, 'banana': 2, 'orange': 8, 'grape': 3}

# 按键升序
dict(sorted(d1.items(), key=lambda x: x[0]))

# 按值升序
dict(sorted(d1.items(), key=lambda x: x[1]))

# 按值降序
dict(sorted(d1.items(), key=lambda x: x[1], reverse=True))
{'apple': 5, 'banana': 2, 'grape': 3, 'orange': 8}
{'banana': 2, 'grape': 3, 'apple': 5, 'orange': 8}
{'orange': 8, 'apple': 5, 'grape': 3, 'banana': 2}

10.4 练习

  1. 统计赵元任创作的文言同音文《石室施氏食狮史》中各字符出现的频次。
s = '石室诗士施氏,嗜狮,誓食十狮。施氏时时适市视狮。十时,适十狮适市。是时,适施氏适市。施氏视是十狮,恃矢势,使是十狮逝世。氏拾是十狮尸,适石室。石室湿,氏使侍拭石室。石室拭,施氏始试食是十狮尸。食时,始识是十狮尸,实十石狮尸。试释是事'
# 统计 s 中各字符出现的频次