Python学习系列之字典

一、字典的定义

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字典包含了以下内置函数:

序号函数及描述实例
1len(dict)
计算字典元素个数,即键的总数。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

>>> len(dict)
3
2str(dict)
输出字典,以可打印的字符串表示。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}

>>> str(dict)
"{'Name': 'Runoob', 'Class': 'First', 'Age': 7}"
3type(variable)
返回输入的变量类型,如果变量是字典就返回字典类型。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
>>> type(dict)
<class 'dict'>
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字典包含了以下函数:

序号函数及描述
1radiansdict.clear()
删除字典内所有元素
2radiansdict.copy()
返回一个字典的浅复制
3radiansdict.fromkeys(seq[, val])
创建一个新字典,以序列seq中元素做字典的键,val为字典所有键对应的初始值
4radiansdict.get(key, default=None)
返回指定键的值,如果值不在字典中返回default值
5key in dict
如果键在字典dict里返回true,否则返回false
6radiansdict.items()
以列表返回可遍历的(键, 值) 元组数组
7radiansdict.keys()
返回一个迭代器,可以使用 list() 来转换为列表
8radiansdict.setdefault(key, default=None)
和get()类似, 但如果键不存在于字典中,将会添加键并将值设为default
9radiansdict.update(dict2)
把字典dict2的键/值对更新到dict里
10radiansdict.values()
返回一个迭代器,可以使用 list() 来转换为列表
11pop(key[,default])
删除字典给定键 key 所对应的值,返回值为被删除的值。key值必须给出。 否则,返回default值。
12popitem()
随机返回并删除字典中的一对键和值(一般删除末尾对)。
12dict.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 语句让代码显得有点冗余和不易读,Pythondefaultdict 改善上述代码。

>>> 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 的判语句没有了。

defaultdictdict 的一个子类。对 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 实现。如果有太多的分支判断,还可以使用字典来代替。因为字典的值可以是任何类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值