百度360必应搜狗淘宝本站头条
当前位置:网站首页 > IT知识 > 正文

RealPython 基础教程:Python 字典用法详解

liuian 2024-11-28 00:42 50 浏览

在连续编写了5篇和 list 相关的文章之后,我们继续《RealPython 基础教程》这个系列。


今天,我们要学习的数据结构是字典(dict)。


dict 是一个包含若干对象的集合。它和 list 有以下共同的特征:

  • 它们都是可变的
  • 它们都是动态的,可根据需要自行伸缩大小。
  • 它们都可以嵌套使用。一个 list 可包含另一个 list,一个 dict 也可以包含另一个 dict。dict 也可以包含 list 等其他对象。


当然,dict 和 list 也是有很大区别的。

  • list 中的元素是通过其位置索引来访问的
  • dict 中的元素则是通过键值(key)来访问的


我们接下来详细了解一下 dict 的用法、特性和使用限制。



【定义一个 dict】

字典是 Python 语言对关联数组这种数据结构的实现。一个 dict 由一组键值对(key-value)组成。每个键值对可将 key 映射到和它关联的 value 上。


我们可以通过使用大括号({})包含一系列以逗号分隔的键值对来定义一个 dict。键值对中的 key 和 value 以冒号来分隔

其形式为:

d = {
    <key>: <value>,
    <key>: <value>,
      .
      .
      .
    <key>: <value>
}


下边我们定义一个 dict,用以存储美国职业棒球队联盟的信息。这个 dict 将各球队所属的地区映射到队名上。

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }

可以用下图直观地表示这个映射结构:


还可以使用内置的 dict() 函数来创建一个 dict 对象传入 dict() 函数的参数应该是一个包含 key-value 键值对的序列,比如由 tuple 对象组成的 list。

这种创建方法形式如下:

d = dict([
    (<key>, <value>),
    (<key>, <value),
      .
      .
      .
    (<key>, <value>)
])


那么,上文中的 MLB_team 也可以采用这种方法来定义:

>>> MLB_team = dict([
...     ('Colorado', 'Rockies'),
...     ('Boston', 'Red Sox'),
...     ('Minnesota', 'Twins'),
...     ('Milwaukee', 'Brewers'),
...     ('Seattle', 'Mariners')
... ])


如果 key 的值是简单的字符串,它们可被指定为 dict() 函数的关键字参数

这样,又有了一种定义 MLB_team 的方式:

>>> MLB_team = dict(
...     Colorado='Rockies',
...     Boston='Red Sox',
...     Minnesota='Twins',
...     Milwaukee='Brewers',
...     Seattle='Mariners'
... )


一旦 dict 对象被定义,你就可以像 list 那样显示其中的内容。上述三种定义方式显示效果是一致的:

>>> type(MLB_team)
<class 'dict'>


>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}


我们看到,dict 中的元素按其定义时的顺序显示了出来。但是,这不意味着你就可以按照这个顺序(索引)来依次获取这些元素。dict 中的元素不是通过数值索引来访问的

>>> MLB_team[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 1


【访问 dict 中的元素】

那么,我们该如何访问 dict 中的元素呢?

答案是:通过在中括号([])中指定元素的 key 来从 dict 中获取与 key 对应的 value 值

>>> MLB_team['Minnesota']
'Twins'
>>> MLB_team['Colorado']
'Rockies'


如果 key 不存在于 dict 中,Python 会抛出异常:

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Toronto'


向 dict 中添加元素的方法很简单,只需要执行一个键值对赋值操作就行了。

>>> MLB_team['Kansas City'] = 'Royals'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners', 'Kansas City': 'Royals'}


如果想更新 dict 中的元素只需要为 key 赋一个新的 value 就行了。

>>> MLB_team['Seattle'] = 'Seahawks'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Seahawks', 'Kansas City': 'Royals'}


可以通过 del 语句来删除 dict 中的元素,你需要在 del 后指定要删除的那个 key。

>>> del MLB_team['Seattle']
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Kansas City': 'Royals'}


【对比 dict 键值和 list 索引】

在上边的例子中,如果 key 不存在于 dict,或使用数值索引来访问 dict 中的元素,Python 解释器都会抛出一个 KeyError 的异常。

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Toronto'
>>>
>>> MLB_team[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 1

这两个错误实际是同一个错误。[1] 这种形式看似是数值索引,但实际上并非如此。


本文后边会提到:任何一个不可变类型的对象都可以作为 dict 的 key。整数也可以。

>>> d = {0: 'a', 1: 'b', 2: 'c', 3: 'd'}
>>> d
{0: 'a', 1: 'b', 2: 'c', 3: 'd'}
>>>
>>> d[0]
'a'
>>> d[2]
'c'

这里,d[0] 和 d[2] 中的 0 和 2 看似索引,但它们与元素在 dict 中的位置顺序毫无关系。Python 将其解释为 dict 的 key。

如果你倒序定义上边这个 d,你再使用同样的 key 来访问,得到的值仍是相同的。

>>> d = {3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> d
{3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> d[0]
'a'
>>> d[2]
'c'


通过 key 来访问 dict 元素和通过索引来访问 list 中的元素,二者语法相似,但是你却不可以像 list 那样来操作 dict。

>>> d = {3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> type(d)
<class 'dict'>
>>>
>>> d[-1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: -1
>>>
>>> d[0:2]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'slice'
>>>
>>> d.append('e')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'dict' object has no attribute 'append'

dict 不支持索引、切片和 append 这些访问和操作方法!


虽然不能通过位置顺序(索引)来访问 dict 中的元素,Python 却可以保证 dict 中元素的顺序按它们被定义时的那样得以保留。

>>> d = {3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> d
{3: 'd', 2: 'c', 1: 'b', 0: 'a'}
>>> d[-1] = 'e'
>>> d
{3: 'd', 2: 'c', 1: 'b', 0: 'a', -1: 'e'}
>>> d[5] = 'f'
>>> d
{3: 'd', 2: 'c', 1: 'b', 0: 'a', -1: 'e', 5: 'f'}
>>>
>>> del d[1]
>>> d
{3: 'd', 2: 'c', 0: 'a', -1: 'e', 5: 'f'}

定义时是什么顺序,输出时就是什么顺序。

新的元素会被“添加到尾部”。

删除一个元素后,剩余元素仍保持原来的顺序。

需要注意:dict 的这个特性仅在 Python 3.6 之后的版本支持。



【渐进式构建一个 dict】

如果我们已经提前知道了所有的 key 和 value,就可以使用大括号或者键值对序列的方式来定义 dict。但如果你想动态创建一个 dict,那该怎么办?

你可以先创建一个空的 dict,然后逐个添加新的 key 和 value

>>> person = {}
>>> type(person)
<class 'dict'>


>>> person['fname'] = 'Joe'
>>> person['lname'] = 'Fonebone'
>>> person['age'] = 51
>>> person['spouse'] = 'Edna'
>>> person['children'] = ['Ralph', 'Betty', 'Joey']
>>> person['pets'] = {'dog': 'Fido', 'cat': 'Sox'}


以这种方式创建的 dict,其访问方式和其他方式创建的 dict 是一样的。

>>> person
{'fname': 'Joe', 'lname': 'Fonebone', 'age': 51, 'spouse': 'Edna',
'children': ['Ralph', 'Betty', 'Joey'], 'pets': {'dog': 'Fido', 'cat': 'Sox'}}


>>> person['fname']
'Joe'
>>> person['age']
51
>>> person['children']
['Ralph', 'Betty', 'Joey']


你需要使用额外的索引或 key 来访问 dict 中的子 list 或 子 dict 中的值。

>>> person['children'][-1]
'Joey'
>>> person['pets']['cat']
'Sox'


这个例子展示了 dict 的另一特征:dict 中的 value 可不必是相同类型。person 中,某些 value 是字符串,一个 value 是整数,一个 value 是 list,还有一个 value 是另一个 dict。

与之相似,dict 中的 key 也不必是相同类型

>>> foo = {42: 'aaa', 2.78: 'bbb', True: 'ccc'}
>>> foo
{42: 'aaa', 2.78: 'bbb', True: 'ccc'}
>>>
>>> foo[42]
'aaa'
>>> foo[2.78]
'bbb'
>>> foo[True]
'ccc'


dict 元素的 key 和 value 上的限制如此之少,使得它具有非常广泛的用途。



【dict 键值(key)的使用约束】

虽然几乎任何类型的值都可用作 dict 的 key,但是对于 key 的使用,还是存在一些约束条件。


首先,dict 中不能存在重复的 key。每个 key 对应于一个 value。如果将 value 赋值给一个已存在的 key,它会替换原来的 value。

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }


>>> MLB_team['Minnesota'] = 'Timberwolves'
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Timberwolves',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}


同样,如果你在初始化 dict 时两次使用了同一个 key,后者将会覆盖前者。

...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Timberwolves',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners',
...     'Minnesota': 'Twins'
... }
>>> MLB_team
{'Colorado': 'Rockies', 'Boston': 'Red Sox', 'Minnesota': 'Twins',
'Milwaukee': 'Brewers', 'Seattle': 'Mariners'}


其次,dict 中的 key 必须属于不可变类型

我们在上边的例子中已看到,像整数、浮点数、字符串、布尔值这些不可变类型值都可用作 key。

tuple 也可用作 dict 的 key,因为它也是不可变的。

>>> d = {(1, 1): 'a', (1, 2): 'b', (2, 1): 'c', (2, 2): 'd'}
>>> d[(1,1)]
'a'
>>> d[(2,1)]
'c'


而 list 和 dict 不可用作 key,因为这两者都是可变数据类型。

>>> d = {[1, 1]: 'a', [1, 2]: 'b', [2, 1]: 'c', [2, 2]: 'd'}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'


这里,我们看到报错提示:unhashable type。为什么会有这样的报错?

技术上讲,用作 dict 的 key 的对象必须是不可变类型,这句话并不十分正确。更精确的说法是:用作 key 的对象必须是可哈希的(hashable)。它可以传递给一个哈希函数,从而能够计算出一个可用来查表和比对的哈希值。


Python 内置的 hash() 函数返回一个可哈希对象的哈希值,如果此对象不可哈希,hash() 函数会抛出异常。

>>> hash('foo')
-2375898492641405263
>>> hash([1, 2, 3])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Python 中所有内置的不可变类型都是可哈希的,list 和 dict 这些可变的容器类型则不可哈希。

但是,我们以后会遇到可哈希的可变类型对象。这是后话,按下不表。



【dict 元素值(value)的使用约束】

dict 中 value 的类型约束很简单:没有限制!

任何类型的对象都可用作 dict 的 value



【适用于 dict 的运算符和内置函数】

我们已经熟悉了许多运算符和内置函数,它们可用于字符串、list 和 tuple 对象上。有些也适用于 dict。


in 和 not in 可用于测试给定的 key 是否存在于 dict 中

...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }


>>> 'Milwaukee' in MLB_team
True
>>> 'Toronto' in MLB_team
False
>>> 'Toronto' not in MLB_team
True


如果访问 dict 中不存在的 key,Python 会抛出异常。我们可以在短路求值中使用 in 来避免异常的发生。

>>> MLB_team['Toronto']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'Toronto'
>>>
>>> 'Toronto' in MLB_team and MLB_team['Toronto']
False


len() 函数可用来计算 dict 中键值对的个数

>>> MLB_team = {
...     'Colorado' : 'Rockies',
...     'Boston'   : 'Red Sox',
...     'Minnesota': 'Twins',
...     'Milwaukee': 'Brewers',
...     'Seattle'  : 'Mariners'
... }
>>> len(MLB_team)
5


【dict 内置方法】

我们简单列举一下 dict 提供的一些内置方法。

d.clear(): 清空一个 dict 对象

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}


>>> d.clear()
>>> d
{}


d.get(<key>[, <default>]):若 key 存在于 dict 中,返回其 value,否则返回 default 指定的值

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d.get('b')
20
>>> d.get('z')
>>>
>>> d.get('z', -1)
-1


d.items():返回一个包含 dict 中键值对(key, value,)的 list

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}
>>> d.items()
dict_items([('a', 10), ('b', 20), ('c', 30)])
>>>
>>> list(d.items())
[('a', 10), ('b', 20), ('c', 30)]
>>> list(d.items())[1][0]
'b'


d.keys():返回一个包含 dict 中所有 key 的 list

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}
>>> list(d.keys())
['a', 'b', 'c']


d.valus():返回一个包含 dict 中所有 value 的 list

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d
{'a': 10, 'b': 20, 'c': 30}


>>> list(d.values())
[10, 20, 30]


注意:items()、key() 和 values() 返回的是一个称为 view 的对象,你需要使用 list() 将其转换为 list。


d.pop(<key>[, <default>]):从 dict 中删除 key 指定的元素,并返回其 value。若 key 不存在:若 指定了 default,则返回 default;否则抛出异常

>>> d = {'a': 10, 'b': 20, 'c': 30}
>>> d.pop('b')
20
>>> d
{'a': 10, 'c': 30}
>>>
>>> d.pop('z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'z'
>>>
>>> d.pop('z', -1)
-1
>>> d
{'a': 10, 'c': 30}


d.popitem():删除 dict 中最后添加的元素,并以 tuple 的形式将其返回。若 dict 为空,抛出异常

>>> d = {'a': 10, 'b': 20}
>>> d.popitem()
('b', 20)
>>> d.popitem()
('a', 10)
>>> d.popitem()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'popitem(): dictionary is empty'


d.update(<obj>):将 obj 合并到 dict 中

obj 可以是一个 dict 或一个包含键值对的序列。

>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d2 = {'b': 200, 'd': 400}


>>> d1.update(d2)
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}
>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d1.update([('b', 200), ('d', 400)])
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}

被合并的值也可以是关键字参数列表。

>>> d1 = {'a': 10, 'b': 20, 'c': 30}
>>> d1.update(b=200, d=400)
>>> d1
{'a': 10, 'b': 200, 'c': 30, 'd': 400}


合并算法为:若原 dict 中不存在 obj 中的 key,则将 obj 中的 key-value 添加到原 dict;若存在,则 obj 中的 key-value 会覆盖原 dict 中的 key-value




温馨提示:

1. 我们后续将尝试从 Python 源码层面探索 dict 的底层数据结构和相关算法,敬请关注。

2. 本文首发于微信公众号:python学与思。

python学与思分享优质原创 Python 教程和技术文章,整理 Python 常用库和开源框架的使用文档,汇集 Python 常见疑难问题解决方法。realpython.cn 和你一起学 Python!



【近期热门文章】

  1. 一文掌握 Python 迭代器的原理
  2. 从 Python 列表的特性来探究其底层实现机制
  3. 列表推导式:简洁高效更具 Python 风格的列表创建方法

相关推荐

声卡驱动64位(创新声卡kx 3552 win10 64位驱动补丁)

根据我的了解,惠普战66声卡通常使用RealtekHighDefinitionAudio驱动程序。然而,具体的驱动版本可能会因操作系统和硬件配置而有所不同。为了确保获得最佳的音频性能和兼容性,建...

笔记本蓝牙驱动怎么安装(笔记本蓝牙驱动安装步骤)

我们在使用电脑的时候,要想进行一些远程操作,那么蓝牙的功能是非常重要的,可是一些朋友因为电脑没有蓝牙驱动程序而无法启动蓝牙,现在就来说说蓝牙驱动安装的详细操作步骤吧。第一步:首先鼠标右键点击开始并选择...

win8系统多大(win8.1系统多大)

win8更大,安装后占C盘约15G,win7约占8-10G.个人觉得win8更好,如果要安装的话,最好给C盘留100G空间,这样方便以后软件的安装以及系统的持久运行。对于系统的选择,一是看是该系统否...

我的邮箱怎么填写(我的邮箱地址怎么填写)

首先进入写邮件界面,在收件人一栏输入收件邮箱,邮箱格式为帐号+@+域名,然后正确填写格式,在主题处要突出邮件的主旨,让别人知道要传递的事情,比如安排、询问等,在正文中开头是尊称;就填写上你的邮件地址就...

win11系统体验版(win10体验win11)

要体验最新的Win11系统,首先需要检查电脑是否符合Win11的硬件要求,例如处理器、存储、显卡等。如果符合要求,可以前往微软官网下载Win11系统的ISO镜像文件,然后将其写入U盘或DVD光盘。接着...

可以免费主题的软件下载(有什么可以免费弄主题的软件)
可以免费主题的软件下载(有什么可以免费弄主题的软件)

步骤如下:1.我们首先打开vivo手机,在vivo手机自带的APP找到I主题,然后打开I主题,会在打开的时候看到精选里面包含了:主题,字体,铃声,息屏和动态壁纸。2.我们在我们在此页面的右上角找到一个放大镜的标识,点击,然后在弹出的页面输...

2025-11-11 06:55 liuian

怎么设置路由器ip(怎么设置路由器IP地址成2网段)

设置Wifi路由器的IP地址需要登录路由器管理界面。一般来说,路由器的管理地址为192.168.1.1或192.168.0.1,具体地址可以在路由器说明书或者设备背面上找到。下面是具体操作步骤:1....

ie8浏览器是什么意思(ie8浏览器是什么样子的)
ie8浏览器是什么意思(ie8浏览器是什么样子的)

IE8浏览器发布于2009年3月,携手Windows7,安全性得到非常大的增强,可以下载超过4G的文件,也是微软第一个64位版浏览器。微软的IE浏览器,版本是8——11原名叫MicrosoftInternetExplorer是微软...

2025-11-11 05:55 liuian

怎么登陆qq邮箱(163邮箱怎么登陆qq邮箱)
怎么登陆qq邮箱(163邮箱怎么登陆qq邮箱)

1.以苹果iPhone12、iOS15.3为例。选qq邮箱在苹果手机邮件应用页,点击“qq邮箱”选项。2.点下一步输入帐号密码,点击“下一步”。3.验证登录验证完成后,进行登录即可。...

2025-11-11 05:05 liuian

win7纯净旗舰版下载(win7 纯净版)

下载win7纯净版方法如下:在电脑上打开搜索软件,在搜索框里搜寻微软官方网址,打开官网后,第一条进入找到系统版本选择WIN7纯净版,点击立即下载将下载地址设置为本地C盘,下载进度100%后就下载成功...

大白菜重装系统详细步骤(大白菜重装系统步骤和详细教程)

u盘大白菜重装系统的步骤~~1、首先将u盘制作成大白菜u盘启动盘,重启电脑等待出现开机画面按下启动快捷键,选择u盘启动进入到大白菜主菜单,选取“【02】运行大白菜Win8PE装机维护版(新机器)”选项...

office plus官方网站(officeplus官方网站公众号)

1、选中你想要添加翻页的ppt页面,我们这里以这个ppt的第二个页面为例。;2、在页面上方的菜单栏找到“切换'这个选项,选择”切换“中的”页面卷曲“动画效果。;3、设置完毕后,如果你想要选择翻...

u盘制作启动盘后如何恢复原来的样子

可以通过U盘启动盘制作工具的恢复普通盘功能将制作了启动盘的U盘恢复为一个普通U盘,这类制作工具核心相同,都可以实现删除隐藏启动文件的功能,下面以电脑店启动盘制作工具为例:1、将U盘插入电脑,然后运行电...

xp系统安装版免费版华为版(windows xp 安装版)

1、点击主界面中的【设置】进入到设置界面,然后向下滑动即可找到【开发者选项】,点击进入。2、点击【开发者选项】右边的按钮打开此功能,然后在弹出的提示框中选择【确定】。值得注意的是,启用这个功能可能会导...

手机网页自动翻译插件(手机网页自动翻译插件免费版)

找到了吗你好;苹果自带浏览器添加书签按也是要占用手机内存的,自带浏览器的安装包太大,会影响手机运行的,你可以下载一个QQ浏览器。它的安装包很小,不影响手机运行,它使用的极速内核,有着神速一般的浏览体验...