字典
约 3197 字大约 11 分钟
2025-04-04
字典初识
我们来看下面的一个例子:
name_lst = ['张三', '李四', '王二麻子', '小桃红']
id_lst = [18, 9, 25, 50]
其中,列表 name_lst
中存储的是同学的名字,id_lst
中存储的是对应同学的学号。例如,新力
的学号是 18
。
如果我们要查找张三的学号,就要去另一个列表中找到其索引对应的学号值,例如:
name_lst[0]
id_lst[0]
这样的操作虽然也能满足我们的需求,但是显然有些繁琐。而且一旦任何一个列表中的索引发生了变化(比如进行了插入或者删除数据的操作),就要对另一个列表进行同样的改动,否则会造成混乱。
如果我们使用字典来进行这一类操作,就可以避免这样的麻烦。
字典也是 Python 中的基本数据类型之一。字典是 Python 中唯一一种包含键值对的数据类型,字典能够将数据和数据之间进行关联。字典的关键字是 dict
字典的定义方法是这个样子的:dic = {'键': '值'}
,具体的例子就是:
dic = {'只因': ['开车', '唱', '跳'], '张三': 9, 25: '李四', True: '秀', (1, 2, 3): '王二麻子'}
通过键可以准确地找到其对应的值:
print(dic['张三'])
在这里补充一个概念 哈希
,在 Python 中一般可以这样认为:
- 可变数据类型不可哈希
- 不可变数据类型可哈希
目前我们学到的可变数据类型有:列表和字典;不可变数据类型有:整型、字符串、布尔值和元组
Python 字典的底层存储结构是哈希表,这也就意味着字典的键必须是不可变数据类型(也就是可哈希)且唯一(字典中的键只能存在一个)。如果字典中的键出现了重复,后面的键值对会覆盖前面的键值对
字典的值可以是任意数据类型
字典本身也是一个可变数据类型:
dic = {{'a': 1}: 'alice'}
print(dic)
运行上面的代码会报错,错误原因是字典是不可哈希的数据类型。也就是说,字典是可变的
Traceback (most recent call last):
File "<python-input-100>", line 1, in <module>
dic = {{'a': 1}: 'alice'}
^^^^^^^^^^^^^^^^^^^
TypeError: unhashable type: 'dict'
字典元素的增加
字典的增加操作可以通过 dic['键'] = '值'
的方式实现:
dic = {'key': 1}
dic['alice'] = 89
print(dic) # {'key': 1, 'alice': 89}
这种通过赋值的方法增加变量的方法有些”暴力“,因为如果字典中原本存在相同的键,赋值操作将把原来的键对应的值替换为新值:
dic = {'key': 1, 'alice': 18}
dic['alice'] = 89
print(dic) # {'key': 1, 'alice': 89}
还有一种相对”温柔“的增加字典元素的方法,.setdefault()
。通过这种方法,如果原字典中已经有了同样的键,返回值为改键对应的值,不会进行修改操作。如果原字典中不存在这样的值,将会增加新的键值对。值默认为 None
,也可以自定义要添加的值。范围值为增加之后的键对应的新值。例如:
dic = {'key': 1}
print(dic.setdefault('key')) # 1
print(dic.setdefault('tom')) # None
print(dic.setdefault('bob', 89)) # 89
print(dic) # {'key': 1, 'tom': None, 'bob': 89}
对于 .setdefault()
的返回值,可以这样记忆:最终字典的键对应的值是什么,就返回什么
.setdefault()
方法是通过两个步骤进行的:
- 先通过减去字典中查找,如果键存在,返回对应的值,不会继续执行第二步;如果键不存在,返回将要赋给该键的值,默认为
None
,去执行第二步。 - 将键和值添加到字典中
字典的删除
字典的删除主要有 .clear()
、.pop()
、.popitem()
和 del
四种方法。
需要注意的是,字典没有 .remove()
方法。
.clear()
方法用来清空字典,使用该方法后,会得到一个空字典:
dic = {'key': 1, 'aaa': 'bbb'}
dic.clear() # 字典是可变数据类型,可以直接用方法来修改,不必重新赋值
print(dic) # {}
.pop()
方法需要输入想要删除的键作为参数,返回的是被删除的键对应的值:
dic = {'key': 1, 'aaa': 'bbb'}
print(dic.pop('key'))
需要注意一点,如果要删除的键并不存在于字典中,会报错:
>>> dic = {'key': 1, 'aaa': 'bbb'}
>>> dic.pop('bbb')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'bbb'
这时,我们可以给 pop
指定一个默认值,这样如果没有这个键的话,将会返回默认值,而非报错:
>>> dic = {'key': 1, 'aaa': 'bbb'}
>>> dic.pop('bbb', 'nothing found!')
'nothing found!'
这样就可以实现批量处理字典时,如果键存在则删除,如果键不存在则忽略,而不会报错的需求。
.popitem()
是随机删除。但是在 Python3 和最新版本的 Python2.7 中,默认删除字典的最后一组键值对,返回值为删除掉的键值对元组(注意,是元组,而不是像 .pop()
一样放回的是值):
dic = {'key': 1, 'aaa': 'bbb'}
print(dic.popitem()) # ('aaa', 'bbb')
与列表不同的是,字典中没有 remove
方法。
字典中 del
方法的用法和列表十分相似,如果不指定要删除的键,将会删除整个字典:
dic = {'key': 1, 'aaa': 'bbb'}
del dic
print(dic)
代码运行后报错,因为 dic 已经被完全删除了
Traceback (most recent call last):
File "C:/Users/Sure/PyProject/day05/01 exercise.py", line 80, in <module>
print(dic)
NameError: name 'dic' is not defined
我们也可以通过指定键的方法,删除特定的键值对:
dic = {'key': 1, 'aaa': 'bbb'}
del dic['aaa']
print(dic) # {'key': 1}
字典的修改
字典的修改有两种形式,第一种是用暴力增加的方法 dic['键'] = '值'
对已经存在的键进行修改;第二种是通过 .update()
方法来合并两个字典
使用 dic['键'] = '值'
进行修改,当字典中存在指定的键时,该键对应的值将会被替换为新的值:
dic = {'key': 1, 'aaa': 'bbb'}
dic['aaa'] = 'BBB' # 修改
dic['ss'] = 'BBB' # 增加
print(dic) # {'key': 1, 'aaa': 'BBB', 'ss': 'BBB'}
.update()
方法可以将两个字典合并。update
中输入的字典的级别要高于前面的字典。也就是说,如果新输入的键已经在就字典中存在,该键对应的新值将对替换旧值:
dic = {'key': 1, 'aaa': 'bbb'}
dic.update({'key': 2, 'meet': 23})
print(dic) # {'key': 2, 'aaa': 'bbb', 'meet': 23}
也可以使用 |
合并两个字典,但需要注意区分字典的 |=
和 =|
两种操作的不同。old_dict |= new_dict
等价于 old_dict.update(new_dict)
,是在 old_dict
基础上进行的扩充;而 old_dict = old_dict + new_dict
会创建新的字典对象覆盖掉原有的 old_dict
。这两种操作的结果都是合并两个字典,且有相同键的情况都会用 new_dict
中的值覆盖 old_dict
中的值。但是如果有其他变量引用 old_dict
,那么结果就会有所差别:
old_dict = {1: 1, 2: 2}
old_dict2 = old_dict
new_dict = {1: 2, 3: 3}
old_dict |= new_dict # 在 old_ditc 基础上更新
print(old_dict) # {1: 2, 2: 2, 3: 3}
print(old_dict2) # {1: 2, 2: 2, 3: 3}
print(old_dict is old_dict2) # True
# 注释掉上面的代码后再执行下面的代码
old_dict = old_dict | new_dict # 创建新字典
print(old_dict) # {1: 2, 2: 2, 3: 3}
print(old_dict2) # {1: 1, 2: 2}
print(old_dict is old_dict2) # False
字典的查找
字典可以直接通过键来查找值,不过这种查找方式相对“暴力”:当键存在时,返回对应的值;当键不存在时,程序会报错:
dic = {'key': 1, 'aaa': 'bbb'}
print(dic['aaa']) # 'bbb'
print(dic['bbb']) # 程序报错
因为这种直接查找的方法当键不存在时会报错,有时我们需要使用 .get()
方法:当键存在时,返回键对应的值;当键不存在时,返回 None:
dic = {'key': 1, 'aaa': 'bbb'}
print(dic['aaa']) # 'bbb'
print(dic['bbb']) # None
我们甚至可以改变键不存在时的返回值:
print(dic.get('bbb', '没有找到啊'))
我们也可以通过 .keys()
、.values()
和 .items()
方法获取字典全部的键、值和键值对。这三个方法的返回值都是一种 高仿列表
,可以迭代但不支持索引。我们可以通过list函数将返回的高仿列表转化为普通列表:
dic = {'key': 1, 'aaa': 'bbb'}
print(dic.keys())
print(dic.values())
print(dic.items())
for i in dic.keys():
print(i)
print(list(dic.values()))
也可以使用 for 循环迭代字典,将会遍历字典的键:
dic = {'key': 1, 'aaa': 'bbb'}
for i in dic:
print(i)
字典的嵌套
有下面这样一个字典:
house = {
101: {
1: {'皮裤男': {'某女': ['小钢炮'], '国际章': ['熊大', '熊二']}},
2: {'林俊杰': ['磨牙']},
},
102: {
1: {'皮裤女': {'林宥嘉': ['说谎', '你是我的眼']}},
2: {'王菲': ['天后', '传奇', '红豆', '笑忘书']},
},
103: {
1: {'韦小宝': {'阿珂': '刺客', '建宁': '公主', '双儿': '丫鬟', '教主老婆': '龙儿'}},
2: {'张无忌': {'灭绝师太': '倚天剑', '金毛狮王': '屠龙刀', '张三丰': '太极拳'}},
},
104: {1: {'西游记': {'大圣': '金箍撸撸棒', '唐僧': '叨逼叨', '八戒': '高老庄主任'}}},
105: {
1: {'水浒传': {'武松': '打老虎', '鲁智笙': '拔树', '林冲': '教头', '宋江': '老大'}},
2: {'官场': {'高俅': '足球'}},
}
}
要想找到里面的 倚天剑
的 剑
字和 熊大
的 熊
字,我们可以这样找到:
print(house[103][2]['张无忌']['灭绝师太'][2])
print(house[101][1]['皮裤男']['国际章'][0][0])
从上面的例子中,我们就可以发现,字典相较于列表是很有优势的:
- 字典查找内容更方便
- 字典查找速度更快
字典还可以简化流程控制的过程。
举个例子,如果我们需要设计这样一个程序,用户输入编号,程序自动返回该编号对应的菜品。如果我们用 if 条件句来实现,将会非常繁琐:
while True:
choose = int(input('请输入数字(1-12):'))
if choose == 1:
print('饺子')
elif choose == 2:
print('粥')
elif choose == 3:
print('面条')
elif choose == 4:
print('肉')
elif choose == 5:
print('土')
elif choose == 6:
print('东南风')
elif choose == 7:
print('切糕')
elif choose == 8:
print('烤全羊')
elif choose == 9:
print('烤骆驼')
elif choose == 10:
print('锅包肉')
elif choose == 11:
print('杀猪菜')
elif choose == 12:
print('乱炖')
else:
print('输入错误,请重新输入!')
如果我们使用字典的方法,只需要这样即可:
dic = {
'1': '饺子',
'2': '粥',
'3': '面条',
'4': '肉',
'5': '土',
'6': '东南风',
'7': '切糕',
'8': '烤全羊',
'9': '烤骆驼',
'10': '锅包肉',
'11': '杀猪菜',
'12': '乱炖',
}
while True:
choose = input('请输入数字(1-12):')
if choose in dic:
print(dic[choose])
else:
print('输入错误,请重新输入!')
我们看到,使用字典之后,代码节省了不少,而且少了很多重复代码。以后如果需要增加或者删改列表,只需要在字典中进行操作即可,不需要对程序进行改动,后期维护也更为便利
字典的创建
我们还可以使用 dict
函数将其他数据类型转成字典。dict
能够转成字典的数据类型需要是一个等长的二级容器,并且每个第二级容器中元素个数是都是 2 个。比如:
data = [('a', 1), ['b', 2], {'c', 3}, {'d': 1, 4: 2}, 'e5']
print(dict(data))
输出的结果为:
{'a': 1, 'b': 2, 3: 'c', 'd': 4, 'e': '5'}
上面的数据被转成了字典。我们发现,容器的数据类型可以是元组、列表、集合、字典,甚至字符串也可以。要注意的是,每个二级容器的元素个数都只能是两个,多了或者少了都会报错。而且因为二级容器的第一个元素要作为键,所以需要是不可变,可哈希的数据类型。
另外,需要注意的是,集合是无序的数据类型,所以键值的顺序无法保证,因此一般不会使用集合创建字典。如果使用字典创建字典,每个键值对算作一个元素,且只会将原字典的键作为数据创建字典
.fromkeys()
方法
.fromkeys()
方法用来批量创建键值对,此方法需要两个参数,参数 1 是一个可迭代对象,将会迭代添加到字典中成为键,参数 2 是这些键共用的值:
dic = {'key': 1, 'key1': 2}
dic1 = dic.fromkeys('abc', 12)
print(dic,dic1) # {'key': 1, 'key1': 2} {'a': 12, 'b': 12, 'c': 12}
这里需要注意的是,.fromkeys()
方法并不是修改字典的方法,而是会创建一个新字典并返回。
另外一个需要注意的是,如果参数 2 是可变数据,所有的值会共用这个数据:
l = []
dic = dict().fromkeys('abc', l)
l.append(2)
print(l, dic) # [2] {'a': [2], 'b': [2], 'c': [2]}
版权所有
版权归属:Shuo Liu