掘金 后端 ( ) • 2024-04-03 12:32

字典(dictionary)与列表类似,都可作为存储数据的容器,可以放入字符串、整数、布尔值、列表或字典等。顾名思义,就像现实生活中查询用的字典一样,通过要查询的“键(key)”,就能够查询到对应的“值(value)”,也是使用频率相当高的数据类型。

创建字典

创建字典有两种方法,创建时必须包含“键(key)”和“值(value)”两个项,键在左侧,值在右侧。字典中的值可以是 Python中 任何类型的对象。但是键必须满足下面三个条件才可以:

  1. 唯一性:字典中的每一个键都是唯一的,即不允许有重复的键。如果尝试为一个已存在的键设置新的值,原有的值会被新值替换。

  2. 不可变性:作为字典键的对象必须是不可变的,这意味着字符串(str)、数字(int、float 等)、元组(tuple,当元组内部元素也是不可变类型时)等不可变类型可以作为键,而列表(list)、字典或其他可变类型的对象则不能直接作为键。

  3. 哈希性:键必须是可哈希的,也就是说,Python 需要能通过键计算出一个哈希码,以便快速找到对应值的位置。Python 内置的不可变类型已经实现了__hash__()方法,使得它们适合作为字典键。

字典和列表的区别在于列表有“顺序性”,列表中的项都有各自的索引值(offset),但字典中的数据是无序的。

使用大括号 {}

使用大括号创建字典是最常见的创建字典方式,使用方法为 {键:值}

下面的代码,第一个键为'name'值为字符串'oxxo',第二个键为'age'值为数字18,第三个键为'eat'值为列表['apple','banana'],第四个键为123值为字符串'Some Numbe',最后打印出a的类型。

a = {'name':'oxxo','age':18,'eat':['apple','banana'], 123: 'Some Number',}
print(type(a))    # <class 'dict'>
print(a[123])  # Some Number

只使用大括号,可以创建一个空的字典。

a = {}
print(type(a));   # <class 'dict'>

使用 dict()

使用dict()创建字典使用dict(键=值),注意键的前后不需要加上引号。

a = dict(name='oxxo', age=18, eat=['apple','banana'])
print(a)          # {'name': 'oxxo', 'age': 18, 'eat': ['apple', 'banana']}
print(type(a));   # <class 'dict'>

dict()函数除了可以创建字典,也可以将有“两个值的二维列表或元组”转换成字典,转换时会将第一个值当作键,第二个当作值。

a = [['x','100'],['y','200'],['z','300']]
b = dict(a)
print(b)    # {'x': '100', 'y': '200', 'z': '300'}

如果是“双字符”的字符列表表或元组,也可以使用dict()转换成字典。

a = ['ab','cd','ef']
b = dict(a)
print(b)    # {'a': 'b', 'c': 'd', 'e': 'f'}

读取字典

读取字典的项时,与列表或元组使用索引值(offset)不同,只要知道字典的键,就能读取对应的值。

使用中括号 []

使用「字典['键']」的方式,就能读取对应的值,如果读取到的是列表或元组,就可以使用读取列表或元组的方式取出对应的数据。

a = {'name':'oxxo', 'age':18, 'eat':['apple','banana']}
b = a['name']
c = a['eat'][0]
print(b)   # oxxo
print(c)   # apple

使用get()方法

使用中括号取值时,如果没有对应的键,就会发生错误,如果要避免这种情况,就可以使用get()方法来取值,使用方法为get('键'),如果有键就会返回值,如果找不到键,就会返回None

a = {'name':'oxxo', 'age':18, 'eat':['apple','banana']}
b = a.get('name')
c = a.get('school')
print(b)   # oxxo
print(c)   # None

修改字典

字典内的所有元素都是可以修改的,修改的方法有两种:

使用中括号 []

通过「字典['键']=新值」的方式,就能将字典中某个键对应的值,修改为新的值。下方代码将 name 对应的值改为 'XXXX',age 对应的值改为换成 100。

a = {'name':'oxxo', 'age':18}
a['name'] = 'XXXX'
a['age'] = 100
print(a)   # {'name': 'XXXX', 'age': 100}

如果修改字典时,键不存在于字典中,会直接加入一个新的键和值,例如下方代码,原本的字典中没有 ok 这个键,所以执行后就会将键为 ok 值为 True 的数据加入字典中。

a = {'name':'oxxo', 'age':18}
a['name'] = 'XXXX'
a['age'] = 100
a['ok'] = True
print(a) # {'name': 'XXXX', 'age': 100, 'ok': True}

使用 setdefault()

setdefault()函数用法和get()类似,都是可以取出某个键的值,但如果字典中没有对应的键,执行setdefault()就会将新的键和值加入字典中,使用的方式为「setdefault('键',值)」,第二个值只针对「不存在的键」才有作用,下方的代码,变量 b 取得的值仍然是 18 (因为 a 原本的 age 就是 18),但 c 取到 True 之后,字典 a 里就会加入 ok 为 True 的项目。

a = {'name':'oxxo', 'age':18}
b = a.setdefault('age', 100)
c = a.setdefault('ok', True)
print(a)   # {'name': 'oxxo', 'age': 18, 'ok': True}
print(b)   # 18
print(c)   # True

删除字典

删除字典数据有三种做法,包括删除个别的键值、清空整个字典或将整个字典移除:

del

使用「del 字典['键']」可以删除字典中指定的键值,如果使用「del 字典」,则会将整个字典删除,下方代码可以看出,删除了键为 name 的字典 a,只剩下 age 一个键,不过如果删除了整个字典 b,读取 b 时就会发生错误。

a = {'name':'oxxo', 'age':18}
del a['name']
print(a)   # {'age': 18}

b = {'name':'oxxo', 'age':18}
del b
print(b)   # name 'b' is not defined

pop()

使用「pop('键')」可以将字典中某个键「获取并删除」,如果没有赋值给任何变数,这个键值就会删除,下方代码会将 name 对应的值从字典 a 中取出并且删除这个键值对,并将 name 赋值给 b ( 注意,有别于列表的 pop() 可为空,字典的 pop('键') 操作一定要有键,不然会发生错误 )。

a = {'name':'oxxo', 'age':18}
b = a.pop('name')
print(a)   # {'age': 18}
print(b)   # oxxo

clear()

使用「字典.clear()」可以将字典中所有键值对删除,变成一个空的字典。

a = {'name':'oxxo', 'age':18}
a.clear()
print(a)   # {}

合并字典

如果要将多个字典合并成一个字典,Python 提供两种方法:

使用两个星号**

使用两个星号「**字典」,会将字典拆解为 keyword arguments 列表,再通过大括号组合,就可以将不同的字典合并为新的字典,下面的代码,a、b、c 就会合并成 d。

a = {'name':'oxxo', 'age':18}
b = {'weight':60, 'height':170}
c = {'ok':True}
d = {**a, **b, **c}
print(d)   # {'name': 'oxxo', 'age': 18, 'weight': 60, 'height': 170, 'ok': True}

使用 update()

使用「字典1.update(字典2)」,会将字典 2 的内容与字典 1 合并,下面的代码,会将 b 和 c 依序和 a 合并。

a = {'name':'oxxo', 'age':18}
b = {'weight':60, 'height':170}
c = {'ok':True}
a.update(b)
a.update(c)
print(a)   # {'name': 'oxxo', 'age': 18, 'weight': 60, 'height': 170, 'ok': True}

取得所有键和值

字典由键和值组成,通过「字典.keys()」能够将所有的键取出变成「dictkeys()」,通过「字典.values()」能够将所有的值取出变成「dictvalues()」,两者都可以通过列表或元组的方法,转换成列表或元组。

a = {'name':'oxxo', 'age':18, 'weight':60, 'height':170}
b = a.keys()
c = a.values()
print(b)         # dictkeys(['name', 'age', 'weight', 'height'])
print(c)         # dictvalues(['oxxo', 18, 60, 170])
print(list(b))   # ['name', 'age', 'weight', 'height']
print(list(c))   # ['oxxo', 18, 60, 170]

使用 in 检查键

in 可以判断某个键是否存在于字典中,使用方法为「键 in 字典」,如果字典中存在这个键,就会返回 True,如果不存在,就返回 Fasle。

a = {'apple':10, 'banana':20, 'orange':30}
print('apple' in a)   # True
print('grap' in a)    # False

复制字典

Python 提供两种复制字典的方法:

copy()

copy() 可以快速复制一个新的字典,使用方式为「字典.copy()」。

a = {'x':10, 'y':20, 'z':30}
b = a.copy()
print(b)   # {'x': 10, 'y': 20, 'z': 30}

deepcopy()

copy() 只是对字典里的数据进行浅拷贝,如果原字典中某个值是一个可变对象(如列表、字典等),那么这个新字典中对应的值仍会指向原来的可变对象。换句话说,浅复制时,对原字典中嵌套的可变对象所做的修改会影响到新复制出的字典。

举例来说,下方的代码执行后,当 a 改变时理应不该影响到 b,但执行结果却发现 b 的内容也跟着改变了。

a = {'x':10, 'y':20, 'z':[100,200,300]}
b = a.copy()
a['z'][0] = 999
print(a)   # {'x': 10, 'y': 20, 'z': [999, 200, 300]}
print(b)   # {'x': 10, 'y': 20, 'z': [999, 200, 300]}

如果要解决这个问题,就必须要 import copy() 模块,使用 deepcopy() 进行深度复制,它会对原字典中所有嵌套的可变对象进行递归复制,就能产生一个完全独立的新字典。

import copy
a = {'x':10, 'y':20, 'z':[100,200,300]}
b = copy.deepcopy(a)
a['z'][0] = 999
print(a)   # {'x': 10, 'y': 20, 'z': [999, 200, 300]}
print(b)   # {'x': 10, 'y': 20, 'z': [100, 200, 300]} 使用 deepcopy 的没有被改变