字典是 Python 中唯一的映射類型,每個(gè)元素由鍵(key)和值(value)構(gòu)成,鍵必須是不可變類型,比如數(shù)字、字符串和元組。
這里先介紹字典的幾個(gè)基本操作,后文再介紹字典的常用方法。
字典可以通過下面的方式創(chuàng)建:
>>> d0 = {} # 空字典
>>> d0
{}
>>> d1 = {'name': 'ethan', 'age': 20}
>>> d1
{'age': 20, 'name': 'ethan'}
>>> d1['age'] = 21 # 更新字典
>>> d1
{'age': 21, 'name': 'ethan'}
>>> d2 = dict(name='ethan', age=20) # 使用 dict 函數(shù)
>>> d2
{'age': 20, 'name': 'ethan'}
>>> item = [('name', 'ethan'), ('age', 20)]
>>> d3 = dict(item)
>>> d3
{'age': 20, 'name': 'ethan'}
遍歷字典有多種方式,這里先介紹一些基本的方式,后文會(huì)介紹一些高效的遍歷方式。
>>> d = {'name': 'ethan', 'age': 20}
>>> for key in d:
... print '%s: %s' % (key, d[key])
...
age: 20
name: ethan
>>> d['name']
'ethan'
>>> d['age']
20
>>> for key in d:
... if key == 'name':
... del d[key] # 要?jiǎng)h除字典的某一項(xiàng)
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: dictionary changed size during iteration
>>>
>>> for key in d.keys(): # python2 應(yīng)該使用這種方式, python3 使用 list(d.keys())
... if key == 'name':
... del d[key]
...
>>> d
{'age': 20}
在上面,我們介紹了兩種遍歷方式:for key in d 和 for key in d.keys(),如果在遍歷的時(shí)候,要?jiǎng)h除鍵為 key 的某項(xiàng),使用第一種方式會(huì)拋出 RuntimeError,使用第二種方式則不會(huì)。
有時(shí),我們需要判斷某個(gè)鍵是否在字典里面,這時(shí)可以用 in 進(jìn)行判斷,如下:
>>> d = {'name': 'ethan', 'age': 20}
>>> 'name' in d
True
>>> d['score'] # 訪問不存在的鍵,會(huì)拋出 KeyError
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'score'
>>> 'score' in d # 使用 in 判斷 key 是否在字典里面
False
字典有自己的一些操作方法,這里只介紹部分常用的方法:
clear 方法用于清空字典中的所有項(xiàng),這是個(gè)原地操作,所以無返回值(或者說是 None)。
看看例子:
>>> d = {'name': 'ethan', 'age': 20}
>>> rv = d.clear()
>>> d
{}
>>> print rv
None
再看看一個(gè)例子:
>>> d1 = {}
>>> d2 = d1
>>> d2['name'] = 'ethan'
>>> d1
{'name': 'ethan'}
>>> d2
{'name': 'ethan'}
>>> d1 = {} # d1 變?yōu)榭兆值?>>> d2
{'name': 'ethan'} # d2 不受影響
在上面,d1 和 d2 最初對(duì)應(yīng)同一個(gè)字典,而后我們使用 d1 = {} 使其變成一個(gè)空字典,但此時(shí) d2 不受影響。如果希望 d1 變成空字典之后,d2 也變成空字典,則可以使用 clear 方法:
>>> d1 = {}
>>> d2 = d1
>>> d2['name'] = 'ethan'
>>> d1
{'name': 'ethan'}
>>> d2
{'name': 'ethan'}
>>> d1.clear() # d1 清空之后,d2 也為空
>>> d1
{}
>>> d2
{}
copy 方法實(shí)現(xiàn)的是淺復(fù)制(shallow copy)。它具有以下特點(diǎn):
看看例子:
# name 的值是不可變對(duì)象,books 的值是可變對(duì)象
>>> d1 = {'name': 'ethan', 'books': ['book1', 'book2', 'book3']}
>>> d2 = d1.copy()
>>> d2['name'] = 'peter' # d2 對(duì)不可變對(duì)象的修改不會(huì)改變 d1
>>> d2
{'books': ['book1', 'book2', 'book3'], 'name': 'peter'}
>>> d1
{'books': ['book1', 'book2', 'book3'], 'name': 'ethan'}
>>> d2['books'].remove('book2') # d2 對(duì)可變對(duì)象的修改會(huì)影響 d1
>>> d2
{'books': ['book1', 'book3'], 'name': 'peter'}
>>> d1
{'books': ['book1', 'book3'], 'name': 'ethan'}
>>> d1['books'].remove('book3') # d1 對(duì)可變對(duì)象的修改會(huì)影響 d2
>>> d1
{'books': ['book1'], 'name': 'ethan'}
>>> d2
{'books': ['book1'], 'name': 'peter'}
和淺復(fù)制對(duì)應(yīng)的是深復(fù)制(deep copy),它會(huì)創(chuàng)造出一個(gè)副本,跟原來的對(duì)象沒有關(guān)系,可以通過 copy 模塊的 deepcopy 函數(shù)來實(shí)現(xiàn):
>>> from copy import deepcopy
>>> d1 = {'name': 'ethan', 'books': ['book1', 'book2', 'book3']}
>>> d2 = deepcopy(d1) # 創(chuàng)造出一個(gè)副本
>>>
>>> d2['books'].remove('book2') # 對(duì) d2 的任何修改不會(huì)影響到 d1
>>> d2
{'books': ['book1', 'book3'], 'name': 'ethan'}
>>> d1
{'books': ['book1', 'book2', 'book3'], 'name': 'ethan'}
>>>
>>> d1['books'].remove('book3') # 對(duì) d1 的任何修改也不會(huì)影響到 d2
>>> d1
{'books': ['book1', 'book2'], 'name': 'ethan'}
>>> d2
{'books': ['book1', 'book3'], 'name': 'ethan'}
當(dāng)我們?cè)噲D訪問字典中不存在的項(xiàng)時(shí)會(huì)出現(xiàn) KeyError,但使用 get 就可以避免這個(gè)問題。
看看例子:
>>> d = {}
>>> d['name']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'name'
>>> print d.get('name')
None
>>> d.get('name', 'ethan') # 'name' 不存在,使用默認(rèn)值 'ethan'
'ethan'
>>> d
{}
setdefault 方法用于對(duì)字典設(shè)定鍵值。使用形式如下:
dict.setdefault(key, default=None)
看看例子:
>>> d = {}
>>> d.setdefault('name', 'ethan') # 返回設(shè)定的默認(rèn)值 'ethan'
'ethan'
>>> d # d 被更新
{'name': 'ethan'}
>>> d['age'] = 20
>>> d
{'age': 20, 'name': 'ethan'}
>>> d.setdefault('age', 18) # age 已存在,返回已有的值,不會(huì)更新字典
20
>>> d
{'age': 20, 'name': 'ethan'}
可以看到,當(dāng)鍵不存在的時(shí)候,setdefault 返回設(shè)定的默認(rèn)值并且更新字典。當(dāng)鍵存在的時(shí)候,會(huì)返回已有的值,但不會(huì)更新字典。
update 方法用于將一個(gè)字典添加到原字典,如果存在相同的鍵則會(huì)進(jìn)行覆蓋。
看看例子:
>>> d = {}
>>> d1 = {'name': 'ethan'}
>>> d.update(d1) # 將字典 d1 添加到 d
>>> d
{'name': 'ethan'}
>>> d2 = {'age': 20}
>>> d.update(d2) # 將字典 d2 添加到 d
>>> d
{'age': 20, 'name': 'ethan'}
>>> d3 = {'name': 'michael'} # 將字典 d3 添加到 d,存在相同的 key,則覆蓋
>>> d.update(d3)
>>> d
{'age': 20, 'name': 'michael'}
items 方法將所有的字典項(xiàng)以列表形式返回,這些列表項(xiàng)的每一項(xiàng)都來自于(鍵,值)。我們也經(jīng)常使用這個(gè)方法來對(duì)字典進(jìn)行遍歷。
看看例子:
>>> d = {'name': 'ethan', 'age': 20}
>>> d.items()
[('age', 20), ('name', 'ethan')]
>>> for k, v in d.items():
... print '%s: %s' % (k, v)
...
age: 20
name: ethan
iteritems 的作用大致相同,但會(huì)返回一個(gè)迭代器對(duì)象而不是列表,同樣,我們也可以使用這個(gè)方法來對(duì)字典進(jìn)行遍歷,而且這也是推薦的做法:
>>> d = {'name': 'ethan', 'age': 20}
>>> d.iteritems()
<dictionary-itemiterator object at 0x109cf2d60>
>>> for k, v in d.iteritems():
... print '%s: %s' % (k, v)
...
age: 20
name: ethan
keys 方法將字典的鍵以列表形式返回,iterkeys 則返回針對(duì)鍵的迭代器。
看看例子:
>>> d = {'name': 'ethan', 'age': 20}
>>> d.keys()
['age', 'name']
>>> d.iterkeys()
<dictionary-keyiterator object at 0x1077fad08>
values 方法將字典的值以列表形式返回,itervalues 則返回針對(duì)值的迭代器。
看看例子:
>>> d = {'name': 'ethan', 'age': 20}
>>> d.values()
[20, 'ethan']
>>> d.itervalues()
<dictionary-valueiterator object at 0x10477dd08>
pop 方法用于將某個(gè)鍵值對(duì)從字典移除,并返回給定鍵的值。
看看例子:
>>> d = {'name': 'ethan', 'age': 20}
>>> d.pop('name')
'ethan'
>>> d
{'age': 20}
popitem 用于隨機(jī)移除字典中的某個(gè)鍵值對(duì)。
看看例子:
>>> d = {'id': 10, 'name': 'ethan', 'age': 20}
>>> d.popitem()
('age', 20)
>>> d
{'id': 10, 'name': 'ethan'}
>>> d.popitem()
('id', 10)
>>> d
{'name': 'ethan'}
事實(shí)上,我們很少直接對(duì)字典進(jìn)行排序,而是對(duì)元素為字典的列表進(jìn)行排序。
比如,存在下面的 students 列表,它的元素是字典:
students = [
{'name': 'john', 'score': 'B', 'age': 15},
{'name': 'jane', 'score': 'A', 'age': 12},
{'name': 'dave', 'score': 'B', 'age': 10},
{'name': 'ethan', 'score': 'C', 'age': 20},
{'name': 'peter', 'score': 'B', 'age': 20},
{'name': 'mike', 'score': 'C', 'age': 16}
]
>>> sorted(students, key=lambda stu: stu['score'])
[{'age': 12, 'name': 'jane', 'score': 'A'},
{'age': 15, 'name': 'john', 'score': 'B'},
{'age': 10, 'name': 'dave', 'score': 'B'},
{'age': 20, 'name': 'peter', 'score': 'B'},
{'age': 20, 'name': 'ethan', 'score': 'C'},
{'age': 16, 'name': 'mike', 'score': 'C'}]
需要注意的是,這里是按照字母的 ascii 大小排序的,所以 score 從小到大,即從 'A' 到 'C'。
>>> sorted(students, key=lambda stu: stu['score'], reverse=True) # reverse 參數(shù)
[{'age': 20, 'name': 'ethan', 'score': 'C'},
{'age': 16, 'name': 'mike', 'score': 'C'},
{'age': 15, 'name': 'john', 'score': 'B'},
{'age': 10, 'name': 'dave', 'score': 'B'},
{'age': 20, 'name': 'peter', 'score': 'B'},
{'age': 12, 'name': 'jane', 'score': 'A'}]
>>> sorted(students, key=lambda stu: (stu['score'], stu['age']))
[{'age': 12, 'name': 'jane', 'score': 'A'},
{'age': 10, 'name': 'dave', 'score': 'B'},
{'age': 15, 'name': 'john', 'score': 'B'},
{'age': 20, 'name': 'peter', 'score': 'B'},
{'age': 16, 'name': 'mike', 'score': 'C'},
{'age': 20, 'name': 'ethan', 'score': 'C'}]
>>> sorted(students, key=lambda stu: (stu['score'], -stu['age']))
[{'age': 12, 'name': 'jane', 'score': 'A'},
{'age': 20, 'name': 'peter', 'score': 'B'},
{'age': 15, 'name': 'john', 'score': 'B'},
{'age': 10, 'name': 'dave', 'score': 'B'},
{'age': 20, 'name': 'ethan', 'score': 'C'},
{'age': 16, 'name': 'mike', 'score': 'C'}]