一、字典的定义
1.1 定义和基本用法
字典是一种是一个无序、以键值对存储可变容器数据类型,数据关联性强、唯一一个映射数据类型。键:必须是可哈希(不可变的数据类型:字符串、数字、元组、bool),值是唯一的且可存储任意类型对象,类似于Java中的Map接口。字典的每个键值 key:value 对用冒号 : 分割,每个键值对之间用逗号 , 分割,整个字典包括在花括号 {} 中,格式如下所示:
d = {key1 : value1, key2 : value2 }
键一般是唯一的,如果重复最后的一个键值对会替换前面的,值不需要唯一。这个特点与字典的底层实现有关,字典是基于哈希表实现的,所以不允许键重复,第二节会细讲。
>>> dict = {'a': 1, 'b': 2, 'b': '3'}
>>> dict['b'] '3'
>>> dict {'a': 1, 'b': '3'}
值可以取任何数据类型,但键必须是不可变的,如字符串,数字或元组。与Java要求相同,可变的话会出现问题,第二节会细讲。
一个简单的字典实例:
dict = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
dict = {}
也可如此创建字典:
dict = dict({ 'abc': 456 })
dict = dict()
1.2 dict函数及其他容器函数
类似于集合set(),列表list(),元组tuple(),可以直接创建相对应的类型,也可以进行强制类型转换。
- tuple函数:将一个序列作为参数,并把它转化为元组,如果参数是元组,将会原样返回。
()
>>> tuple({1:2, 3:4})
(1, 3)
>>> tuple((1,2,3,4))
(1, 2, 3, 4)
>>> tuple({1,2,3,4})
(1, 2, 3, 4)
>>> tuple('1234')
('1', '2', '3', '4')
>>> tuple([1,2,3,4])
(1, 2, 3, 4)
- list函数:将一个元组,字典,集合作为参数,并把它转化为列表,如果参数是列表,将会原样返回。但是对于字典,list只会处理键。
[]
>>> list({1:2, 3:4})
[1, 3]
>>> list((1,2,3,4))
[1, 2, 3, 4]
>>> list({1,2,3,4})
[1, 2, 3, 4]
>>> list('1234')
['1', '2', '3', '4']
>>> list([1,2,3,4])
[1, 2, 3, 4]
- dict函数:可以传递元组列表,并把它转化为字典,如果参数是字典,将会原样返回。
{:}
>>> dict([(1,2)])
{1: 2}
>>> dict({1:2})
{1: 2}
基本语法:
class dict(**kwarg)
class dict(mapping, **kwarg)
class dict(iterable, **kwarg)
参数说明:
- **kwargs -- 关键字参数
- mapping -- 元素的容器。
- iterable -- 可迭代对象
- set函数
{}
>>> set({1:2, 3:4})
{1, 3}
>>> set((1,2,3,4))
{1, 2, 3, 4}
>>> set({1,2,3,4})
{1, 2, 3, 4}
>>> set('1234')
{'2', '1', '4', '3'}
>>> set([1,2,3,4])
{1, 2, 3, 4}
1.3 内置函数
Python字典包含了以下内置函数:
序号 | 函数及描述 | 实例 |
---|---|---|
1 | len(dict) 计算字典元素个数,即键的总数。 | |
2 | str(dict) 输出字典,以可打印的字符串表示。 | |
3 | type(variable) 返回输入的变量类型,如果变量是字典就返回字典类型。 | |
4 | cmp(dict1, dict2) Python2 | >>> cmp({1:2}, {1:2}) 0 >>> cmp({1:2}, {1:3}) -1 >>> cmp({1:2}, {1:1}) 1 >>> cmp({2:2}, {1:2}) 1 |
cmp函数:
(1) 比较字典的长度
如果字典的长度不同,那么用cmp(dict1,dict2)比较大小时,如果字典dict1比dict2长,cmp()返回正值,如果dict2比dict1长,则返回负值。也就是说,字典中的键的个数越多,这个字典就越大
(2) 比较字典的键
如果两个字典的长度相同,那么就比较字典的键;键的比较顺序和keys()方法返回键的顺序相同(相同的键会映射到哈希表的同一个位置,这就保证了对字典键的检查的一致性)。这时,如果两个字典的键不匹配时,对这两个键进行比较就可以了。如果dict1中的第一个不同的键大于dict2中的第一个不同键,cmp()返回正值。
(3)比较字典的值
如果两个字典的长度相同并且它们的键也相同,则用字典中每个相同的键所对应的的值进行比较。一旦出现不匹配的值,就可以对这两个字典进行比较了。如果dict1比dict2中相同的键所对应的值大,cmp()会返回正值。
(4) Exact Match
到此为止,即每个字典有相同的长度、相同的键以及每个键的值也相同时,就说明这两个字典是相同的,cmp()返回0值。
另外,字符串、元组及列表中也有比较方法cmp(),其原理也基本相同。
python 3.4.3 及以上的版本中已经没有cmp函数,被operator模块代替,使用时,需要导入模块:
lt(a,b) 相当于 a<b 从第一个数字或字母(ASCII)比大小
le(a,b)相当于a<=b
eq(a,b)相当于a==b 字母完全一样,返回True,
ne(a,b)相当于a!=b
gt(a,b)相当于a>b
ge(a,b)相当于 a>=b
函数的返回值是布尔哦
Python字典包含了以下函数:
序号 | 函数及描述 |
---|---|
1 | radiansdict.clear() 删除字典内所有元素 |
2 | radiansdict.copy() 返回一个字典的浅复制 |
3 | radiansdict.fromkeys(seq[, val]) 创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值 |
4 | radiansdict.get(key, default=None) 返回指定键的值,如果值不在字典中返回default值 |
5 | key in dict 如果键在字典dict里返回true,否则返回false |
6 | radiansdict.items() 以列表返回可遍历的(键, 值) 元组数组 |
7 | radiansdict.keys() 返回一个迭代器,可以使用 list() 来转换为列表 |
8 | radiansdict.setdefault(key, default=None) 和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default |
9 | radiansdict.update(dict2) 把字典dict2的键/值对更新到dict里 |
10 | radiansdict.values() 返回一个迭代器,可以使用 list() 来转换为列表 |
11 | pop(key[,default]) 删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。 |
12 | popitem() 随机返回并删除字典中的一对键和值(一般删除末尾对)。 |
12 | dict.has_key(key) Python2 如果键在字典dict里返回true,否则返回false |
has_key()已经在Python3中被移出,推荐使用,'key' in dict来判断键是否存在。
hash(): 判断某个对象是否可以做一个字典的键,如果非可哈希类型作为参数传递给 hash()方法,会产生TypeError 错误。返回的是返回 obj 的哈希值。
以上所有返回迭代器的函数在Python 2中返回的是列表。
二、底层实现原理
字典值可以没有限制地取任何python对象,既可以是标准的对象,也可以是用户定义的,但键不行,必须是唯一的不可变的。为什么?
主要原因是字典使用 hash表来实现key和value之间的映射和存储的,hash函数设计的好坏影响着数据的查找访问效率。
(1)哈希表的本质是一个数组,数组中每一个元素称为一个箱子(Python里称为item,Java里称为Entity 内部类),箱子中存放的是键值对。也可以认为索引的数组是简化的哈希表。
(2)通常是将元素的键进行哈希运算,然后把值存储到相应位置。以后每次查找或修改都可以在O(1)的时间内进行。因为查找时候直接计算哈希值就能知道箱子具体位置,类似于数组索引。
(3)此时我们也看出了为什么字典键不允许相同。因为如果键值相同,得到的哈希值也相同,索引位置就相同,无法存储和辨别具体值。
(4)字典键不可变的原因更加明了。如果我们有一个字典键是可变类型。存储到字典中已经计算好了hash值,并且存储好了相应位置的值。但是这个键在后面的代码中发生了变化,此时字典键值也发生了变化。以后可能我们再也没法去访问原来存储的内容了。因为键值对的对应关系和存储的哈希值-值对应关系已经不一致。
哈希函数需要解决哈希冲突问题,设计的越好的哈希函数哈希冲突越多。具体哈希表的概念(哈希函数,装填因子等),设计方法和冲突解决方法可以参照其他博客。
注:王小云教授找到了MD5的哈希碰撞,所以现在MD5不安全,推荐使用SHA256,并且因为这个贡献现在从山大跳到了清华。
两个重要的点需要记住:
1)不允许同一个键出现两次。创建时如果同一个键被赋值两次,前一个值会被覆盖,后一个值会被记住,如下实例:
实例:
dict = {'Name': 'Zara', 'Age': 7, 'Name': 'Manni'}
print "dict['Name']: ", dict['Name']
dict['Name']: Manni
2)键必须不可变,所以可以用数字,字符串或元组等不可变类型充当,所以用列表就不行,如下实例:
实例:
dict = {['Name']: 'Zara', 'Age': 7}
print "dict['Name']: ", dict['Name']
Traceback (most recent call last):
File "test.py", line 3, in <module>
dict = {['Name']: 'Zara', 'Age': 7}
TypeError: list objects are unhashable
提示错误:列表对象不能被哈希,因为列表可变。被哈希会出现问题。
三、字典的操作
3.1 字典遍历
3.1.1 遍历字典的键
对一个字典(或者字典的 keys() 函数)进行迭代将返回字典中的键。在下面的例子中,字典的键为图板游戏 Clue牌的类型:
>>> accusation = {'room': 'ballroom', 'weapon': 'lead pipe',
'person': 'Col. Mustard'}
>>> for card in accusation: # 或者是for card in accusation.keys():
... print(card)
...
room
weapon
person
key()获取字典所有键,list。 以列表返回一个字典所有的键。
3.1.2 遍历字典的值
如果想对字典的值进行迭代,可以使用字典的 values() 函数:
>>> for value in accusation.values():
... print(value)
...
ballroom
lead pipe
Col. Mustard
values()获取字典所有值,list。 以列表返回字典中的所有值。
3.1.3 遍历字典的键值对
为了以元组的形式返回键值对,可以使用字典的 items() 函数,返回可遍历的(键, 值) 元组数组。:
>>> for item in accusation.items():
... print(item)
...
('room', 'ballroom')
('weapon', 'lead pipe')
('person', 'Col. Mustard')
items()获取字典所有键值对,list,每一项是一个元组:(key, value)。类似于Java Map的Entity内部类,保存一个键值对。
3.1.4 iteritems遍历字典
items 方法返回的是(key ,value)组成的列表对象,这种方式的弊端是迭代超大字典的时候,内存瞬间会扩大两倍,因为列表对象会一次性把所有元素加载到内存,更好的方式是使用 iteritems.
for k, v in d.iteritems():
print(k, v)
iteritems 返回的是迭代器对象,迭代器对象具有惰性加载的特性,只有真正需要的时候才生成值,这种方式在迭代过程中不需要额外的内存来装载这些数据。注意 Python3 中,只有 items 方法了,它等价于 Python2 中的 iteritems,而 iteritems 这个方法名被移除了。
Python2:方法iteritems(), iterkeys(), itervalues()与它们对应的非迭代方法一样,不同的是它们返回一个迭代器,而不是一个列表。Python3里移除了这些函数,基础函数全部返回迭代器。
3.3 创建字典
(1)创建空字典:
>>> info = {}
>>> info = dict()
(2)在创建字典的时候初始化字典 :
>>> info = {"name" : 'cold'}
>>> info = dict(name = 'cold') # 更优雅
>>> info = dict(key = 'cold', key2 = 'hot')
list,set,tuple等函数只能接受一个参数,所以无法像上述操作一样创建相应容器。
工厂函数被用来创建字典。如果不提供参数,会生成空字典。调用 dict()方法可以接受字典或关键字参数字典。
>>> dict(zip(('x', 'y'), (1, 2)))
{'y': 2, 'x': 1}
>>> dict([['x', 1], ['y', 2]])
{'y': 2, 'x': 1}
>>> dict([('xy'[i-1], i) for i in range(1,3)])
{'y': 2, 'x': 1}
(3)用工厂的方法创建字典:
>>> fdict=dict(a=3,b=4) #这个比较常用
>>> fdict
{'a': 3, 'b': 4}
必须是字符串,而且不加引号。
(4)使用字典的fromkeys方法可以从列表中获取元素作为键并用None或fromkeys方法的第二个参数初始化:
但是只接受一个值参数,所以所有的键的值相同。
>>> info = {}.fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'])
>>> info
{'blog': None, 'name': None}
>>> info = dict().fromkeys(['name', 'blog'], 'csdn.com')
>>> info
{'blog': 'csdn.com', 'name': 'csdn.com'}
>>> info = dict().fromkeys(['name', 'blog'], 'csdn.com', 'answer.com')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: fromkeys expected at most 2 arguments, got 3
>>> info = dict().fromkeys(['name', 'blog'], ['csdn.com', 'answer.com'])
>>> info
{'blog': ['csdn.com', 'answer.com'], 'name': ['csdn.com', 'answer.com']}
3.3 访问字典里的值
(1)直接利用键去访问值:字典名[键]。 字典是无序的所以不能用索引进行访问。
如果键不存在会报错:KeyError: 'Alice'。
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
print "dict['Name']: ", dict['Name']
print "dict['Age']: ", dict['Age']
dict['Name']: Zara
dict['Age']: 7
(2)但是如果获取不存在的键的值就会触发的一个KeyError异常,字典有一个get方法,可以使用字典get方法更加优雅的获取字典:
>>> info = dict(name= 'cold', blog='www.csdn.com')
>>> info.get('name')
'cold'
>>> info.get('blogname')
None
>>> info.get('blogname', 'csdn')
'linuxzen'
如果键值对不存在,可以给出一个默认值。
3.4 修改字典
(1)Python 字典可以使用键作为索引来访问/修改/添加值。用法同访问字典值相同,直接赋值即可:字典名[键] = 新值。
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict['Age'] = 8 # 更新
dict['School'] = "RUNOOB" # 添加
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
dict['Age']: 8
dict['School']: RUNOOB
(2)Python字典的update方法也可以更新和添加字典:
>>> info = dict(name='cold', blog='answer.com')
>>> info.update({'name':'cold night', 'blogname':'answer'})
>>> info
{'blog': 'answer.com', 'name': 'cold night', 'blogname': 'answer'}
>>> info.update(name='cold', blog='www.answer.com') # 更优雅
>>> info
{'blog': 'www.answer.com', 'name': 'cold', 'blogname': 'answer'}
Python字典的update方法可以使用一个字典来更新字典,也可以使用参数传递类似dict函数一样的方式更新一个字典,上面代码中哦功能的第二个更加优雅,但是同样和dict函数类似,键是变量时也只取字面值
3.4 增加字典元素
向字典添加新内容的方法是增加新的键/值对。或者上述的update方法。
dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
dict['School'] = "菜鸟教程" # 添加信息
print ("dict['School']: ", dict['School'])
dict['School']: 菜鸟教程
3.5 删除字典元素
能删单一的元素也能清空字典。
(1)删除一个字典用del命令,如下实例:
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
del dict # 删除词典
print "dict['Age']: ", dict['Age']
print "dict['School']: ", dict['School']
dict['Age']:
Traceback (most recent call last):
File "test.py", line 8, in <module>
print "dict['Age']: ", dict['Age']
TypeError: 'type' object is unsubscriptable
删除字典后再访问会报错,因为字典不存在。
(2)清空一个字典,字典存在但是没有元素。
dict = {'Name': 'Zara', 'Age': 7, 'Class': 'First'}
dict.clear() # 清空词典所有条目
>>> print("dict['Age']: ", dict['Age'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'Age'
(3)删除字典单个元素。
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
x.pop(1)
print x
{3: 4, 4: 3, 2: 1, 0: 0}
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
del x[1]
print x
{3: 4, 4: 3, 2: 1, 0: 0}
x = {1: 2, 3: 4, 4: 3, 2: 1, 0: 0}
print x.popitem()
print x
{1: 2, 3: 4, 4: 3, 2: 1}
pop()方法(删除字典给定键 key 所对应的值,返回值为被删除的值)
dict.pop(key[,default])。删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 如果减值对不存在,返回default值。
del 全局方法(能删单一的元素也能清空字典)删除字典给定键 key 所对应的值,无返回值。
popitem()方法(随机删除字典中的一对键和值,并返回所删除的键值对),随机的原因是字典没有顺序,并且效率最高,(一般删除末尾对,按照key()返回的顺序)。
四、高级用法
问题一:想对字典的值进行相关计算,例如找出字典里对应值最大(最小)的项。
解决方案一:
假设要从字典 {'a':3, 'b':2, 'c':6}
中找出值最小的项,可以这样做:
>>> d = {'a':3, 'b':2, 'c':6}
>>> min(zip(d.values(), d.keys()))
(2, 'b')
值得注意的是 d.values()
获取字典的全部值,d.keys()
获取字典的全部键,而且两个序列的顺序依然保持一一对应的关系。因此 zip(d.values(), d.keys())
实质上生成的是一个 (value, key)
的序列。min
函数通过比较序列中的元组 (value, key)
找出其最小值。
解决方案二:
除了使用 zip(d.values(), d.keys())
外,还可以使用 dict.items()
方法和生成器推导式来生成 (value, key)
序列,从而传递给 min
函数进行比较:
>>> d = {'a':3, 'b':2, 'c':6}
>>> min((v ,k) for (k, v) in d.items())
(2, 'b')
这里 min
函数的参数 (v ,k) for (k, v) in d.items()
其实是一个生成器推导式(和列表推导式一样,只是把列表推导式的 []
改为 ()
,而且其返回的一个生成器而非列表),由于生成器推导式做为 min
函数的参数,所以可以省略掉两边的括号(不做为参数时写法应该是 ((v ,k) for (k, v) in d.items())
)。
问题二:字典推导式
想把一个元组列表转换成一个字典,例如把 [('a', 1), ('b', 2), ('c', 3)]
转化为 {'a': 1, 'b': 2, 'c': 3}
解决方案:
类似于列表推导式,字典推导式可以方便地从其他数据结构构造字典,例如:
>>> l = [('a', 1), ('b', 2), ('c', 3)]
>>> {k: v for k, v in l}
{'c': 3, 'b': 2, 'a': 1}
字典推导式的规则和列表推导式一样,只是把 []
换成 {}
问题三:寻找字典的交集
假设有两个字典:
d1 = {'a':1, 'b':2, 'c':3, 'd':4}
d2 = {'b':2, 'c':3, 'd':3, 'e':5}
要找出这两个字典中具有公共键的项,即要得到结果 {'b':2, 'c':3}
解决方案:
我们知道一般通过 d.items()
方法来遍历字典,d.items()
方法返回的对象是一个类集合对象,支持集合的基本运算,如取交集、并集等。
>>> dict(d1.items() & d2.items()) # 取交集
{'b': 2, 'c': 3}
此外,d.keys()
返回字典的键,也是一个类集合对象,如果我们只想找出两个字典中键相同的项,可以这样:
>>> { k:d1[k] for k in d1.keys() & d2.keys() }
{'b': 2, 'd': 4, 'c': 3}
这里如果相同的键对应不同的值则去第一个字典中的值。推广开来,如果想排除掉字典中的某些键,可以这样:
>>> { k:d1[k] for k in d1.keys() - {'c', 'd'} } # - 号的含义是集合的差集操作
{'b': 2, 'a': 1}
但有一点需要注意的是,d.values()
返回字典的值,由于字典对应的值不一定唯一,所以 d.values()
一般无法构成一个集合,因此也就不支持一般的集合操作。
问题四:多个字典连接成一个字典
有多个字典,例如:
d1 = {'a':1, 'b':2, 'c':3}
d2 = {'c':4, 'd':5, 'e':6}
想将这多个字典连接为一个字典,或一次性对多个字典进行迭代操作。
解决方案:
使用 collections.ChainMap
:
>>> from collections import ChainMap
>>> chain_dict = ChainMap(d1, d2)
>>> for k, v in chain_dict.items():
print(k, v)
a 1
e 6
d 5
c 3
b 2
ChainMap
将传入的多个字典连接为一个字典,并返回一个 ChainMap
对象,这个对象的行为就像一个单一的字典,我们可以对其进行取值或者迭代等操作。注意到这里键 c
对应的值为 3,如果传入 ChainMap
的字典含有相同的键,则对应的值为先传入的字典中的值。
此外,如果你只想单纯地迭代字典的键值对,可以结合使用 items()
和 itertools.chain()
方法:
>>> from itertools import chain
>>> for k, v in chain(d1.items(), d2.items()):
print(k, v)
a 1
c 3
b 2
e 6
c 4
d 5
这里相同的键会被分别迭代出来。
问题五:保持字典有序
想让字典中元素的迭代顺序和其加入字典的顺序保持一致
解决方案:
通常来说,使用 d.items()
或者 d.keys()
、d.values()
方法迭代出来的元素顺序是无法预料的。例如对字典 d = {'a':1, 'b':2, 'c':3}
迭代:
>>> d = dict()
>>> d['a'] = 1
>>> d['b'] = 2
>>> d['c'] = 3
>>> for k, v in d.items():
print(k, v)
a 1
c 3
b 2
每一次运行结果都可能不同。如果想让元素迭代的顺序和创建字典时元素的顺序一致,就要使用 collections.OrderedDict
代替普通的 dict
(类似于Java的链表List,Set和Map):
>>> from collections import OrderedDict
>>> ordered_d = OrderedDict()
>>> ordered_d['a'] = 1
>>> ordered_d['b'] = 2
>>> ordered_d['c'] = 3
>>> for k, v in ordered_d.items():
print(k, v)
a 1
b 2
c 3
OrderedDict
实际通过维护一个双向链表来记录元素添加的顺序,因此其耗费的内存大约为普通字典的两倍。所以在实际使用中需综合考虑各种因素来决定是否使用 OrderedDict
。
问题六:使字典的键映射多个值
通常情况下字典的键只对应一个值。现在想让一个键对应多个值。
解决方案:
为了使一个键对应多个值,首先需要把多个值放到一个容器中(例如列表或者集合等)。例如有这样一个列表:[('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)]
,我们要将其转换成一个字典,保持元素的键值对应关系,通常我们会写这样的代码:
>>> from pprint import pprint
>>> l = [('a', 1), ('a', 2), ('b', 3), ('b', 4), ('c', 5)]
>>> d = {}
>>> for k, v in l:
if k in d:
d[k].append(v)
else:
d[k] = [v]
>>> pprint(d)
{'a': [1, 2], 'b': [3, 4], 'c': [5]}
但是 if else
语句让代码显得有点冗余和不易读,Python
的 defaultdict
改善上述代码。
>>> from collections import defaultdict
>>> d = defaultdict(list)
>>> for k, v in l:
d[k].append(v)
>>> print(d)
defaultdict(<class 'list'>, {'c': [5], 'b': [3, 4], 'a': [1, 2]})
if else
的判语句没有了。
defaultdict
是 dict
的一个子类。对 dict
来说,如果 key
不存在,则 dict[key]
取值操作会抛出 KeyError
异常,但是 defaultdict
则会返回一个传入 defaultdict
构造器的类的实例(例如一个列表)或者自定义的缺失值。因此在上例中,对于 d[k].append(v)
,当 k
不存在时,则会先执行 d[k] = []
并返回这个空列表,继而将 v
加入到列表中。
传入 defualtdict
构造器的值不一定要是一个类,也可以是一个可调用的函数,当相应的键不在 defualtdict
中时,其默认的值就为这个函数的返回值。
>>> from collections import defaultdict
>>> def zero_default():
return 0
>>> d = defaultdict(zero_default)
>>> d['a'] = 1
>>> d['a']
1
>>> d['b']
0
>>> d.keys()
dict_keys(['b', 'a'])
>>>
利用这样一个特性,我们可以构造无限深度的字典结构:
>>> from collections import defaultdict
>>> import json
>>> tree = lambda: defaultdict(tree)
>>> d = tree()
>>> d['a']['b'] = 1
>>> print(json.dumps(d)) # 为了显示的格式更好看
{"a": {"b": 1}}
这里当执行 d['a']
时,由于相应的键不存在,故返回一个 defaultdict(tree)
,当再执行 d['a']['b'] = 1
时,将键 b
对应的值设为 1 。
五、总结
1、如果不希望 d[x] 在 x 不存在时报错,除了在获取元素时使用 get 方法之外,另外一种方式是用 collections 模块中的 defaultdict,在初始化字典的时候指定一个函数,其实 defaultdict 是 dict 的子类。
2、Python 中没有 switch ... case 语句,这个问题Python之父龟叔表示这个语法过去没有,现在没有,以后也不会有。因为Python简洁的语法完全可以用 if ... elif 实现。如果有太多的分支判断,还可以使用字典来代替。因为字典的值可以是任何类型。