映射是一种可以通过名称来访问其各个值的数据结构。字典是python中唯一的内置映射类型,其中的值不按顺序排列,而是存储在键下。键可以是数字、字符串或元组。
字典是一种键-值对(key-value pair)的数据结构,类似于现实生活中的字典。在现实生活中,字典通过单词(键)来查找对应的定义(值)。同样,在 Python 中,字典通过键(key)来快速查找对应的值(value) 。
很多情况下使用字典比列表更合适,比如:
示例:创建电话簿
假设有一组名字和对应的电话号码,如何高效的存储和查找这些信息?
使用列表存储:
分别创建两个列表:一个存储名字,另一个存储电话号码
names = ['Alice', 'Beth', 'Cecil', 'Dee-Dee', 'Earl']
numbers = ['2341', '9102', '3158', '0142', '5551']
#要查找某个名字对应的电话号码,可以通过名字在 names 列表中找到索引,
#然后用这个索引来访问 numbers 列表中的电话号码:
# 查找 Cecil 的电话号码
index = names.index('Cecil') # 找到 'Cecil' 在 names 列表中的索引
phone_number = numbers[index] # 使用索引获取对应的电话号码
print(phone_number) # 输出: '3158'
这种方法可行,但不够直观和高效:
使用字典存储:
字典允许我们将名字直接作为键,电话号码作为值。这样,我们可以通过名字直接访问对应的电话号码,而不需要额外的查找步骤。
#创建字典 phonebook
phonebook={
'Alice':'2341',
'Beth':'9102',
'Cecil':'3158',
'Dee-Dee':'0142',
'Earl':'5551'
}
#查找Cecil的电话号码
phone_number = phonebook['Cecil']
print(phone_number)#输出3158
字典由键(key)和值(value)组成,这种键-值对称为项(item)。上述代码已经给出了一个简单的字典,在这个示例中,键为名字:'Alice'
, 'Beth'
, 'Cecil',
值为电话号码:'2341'
, '9102'
, '3258'。
每个键与其值之间都用冒号(:)分隔。项之间用逗号分隔,整个字典放在花括号内。
空字典没有任何项,用{}表示。
在字典以及其他映射类型中,键是独一无二的,值可以重复。
可以使用函数dict从其他映射(如字典)或键-值对序列创建字典:
>>> items=[('name','Gumby'),('age',42)]
>>> d=dict(items)
>>> d
{'name': 'Gumby', 'age': 42}
>>> d['name']
'Gumby'
还可以使用关键字实参来调用这个函数:
>>> d=dict(name='Gumdy',age=42)
>>> d
{'name': 'Gumdy', 'age': 42}
不提供任何参数时返回空字典:
>>> empty_dict=dict()
>>> empty_dict
{}
还有一种用copy方法创建字典,在本节后面介绍。
字典的行为在很多方面类似于序列(如列表),但也有其独特之处。以下是字典的一些基本操作:
len(d)返回字典d包括的(键-值)对数。
phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
print(len(phonebook)) # 输出: 3
d[k]返回与键k相关联的值。如果输入的键不存在,则抛出KeyError错误。
phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
print(phonebook['Alice']) # 输出: '2341'
也可以通过d[k]=v的赋值方式修改字典/添加新的键-值对:
phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
# 修改已有的键值对
phonebook['Alice'] = '1234'
print(phonebook) # 输出: {'Alice': '1234', 'Beth': '9102', 'Cecil': '3258'}
# 添加新的键值对
phonebook['Dee-Dee'] = '0142'
print(phonebook) # 输出: {'Alice': '1234', 'Beth': '9102', 'Cecil': '3258', 'Dee-Dee': '0142'}
通过del [k]删除键为k的项。如果输入的键不存在,则抛出KeyError错误。
phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
del phonebook['Alice']
print(phonebook) # 输出: {'Beth': '9102', 'Cecil': '3258'}
可以使用k运算符检查字典中是否存在某个键。若存在则返回True,否则返回False。
phonebook = {'Alice': '2341', 'Beth': '9102', 'Cecil': '3258'}
print('Alice' in phonebook) # 输出: True
print('Dee-Dee' in phonebook) # 输出: False
虽然字典和列表在某些方面有相似之处,但也有一些重要的不同点:
键的类型:字典中的键可以是整数,但并非必须是整数。字典中的键可以是任何不可变
的类型,如浮点数(实数)、字符串或元组。
自动添加:即便是字典中原本没有的键,也可以给它赋值,这将在字典中创建一个新项。
然而,如果不使用append或其他类似的方法,就不能给列表中没有的元素赋值。
成员资格:表达式k in d(其中d是一个字典)查找的是键而不是值,而表达式v in l(其
中l是一个列表)查找的是值而不是索引。
相比于检查列表是否包含指定的值,检查字典是否包含指定的键的效率更高。数据结构
越大,效率差距就越大。
创建一个将人名用作键的字典,每个人都用一个字典表示。字典包含键‘phone'和’addr',它们分别与电话号码和地址相关联。
people={
'Alice':{
'phone':'2341',
'addr':'Foo drive 23'
},
'Beth':{
'phone':'9102',
'addr':'Bar street 42'
},
'Cecel':{
'phone':'3158',
'addr':'Bas avenue 90'
}
}
#电话号码和地址的描述性标签,打印时输出使用
labels={
'phone':'phone number',
'addr':'address'
}
name = input('Name: ')
#要查找电话号码还是地址
request = input('Phone number (p) or address (a)?')
#使用正确的键
if request == 'p':
key = 'phone'
elif request == 'a':
key = 'addr'
#仅当名字是字典包含的键时才打印信息
if name in people:
print("{}'s {} is {}".format(name,labels[key],people[name][key]))
这个程序的运行结果示例:
Name: Alice
Phone number (p) or address (a)?p
Alice's phone number is 2341
在有些情况下,通过在字典中存储一系列命名的值,可让格式设置更容易些。例如,可在字典中包含各种信息,这样只需在格式字符串中提取所需的信息即可。为此,必须使用format_map方法来指出:
>>> phonebook={'Beth':'9102','Alice':'2341','Cecil':'3258'}
>>> phonebook
{'Beth': '9102', 'Alice': '2341', 'Cecil': '3258'}
>>> "Cecil's phone number is {Cecil}.".format_map(phonebook)
"Cecil's phone number is 3258."
示例:使用字典生成html模板
#在模板系统中,常常需要根据动态数据生成 HTML 文档。
#我们可以使用 format_map() 方法,通过字典来填充模板中的占位符。
template = '''
{title}
{title}
{text}
'''
data = {
'title': 'My Home Page',
'text': 'Welcome to my home page!'
}
print(template.format_map(data))
输出:
My Home Page
My Home Page
Welcome to my home page!
clear方法用于删除字典中的所有键值对,使字典变为空字典。调用后,字典会变成一个空字典(即 {}
),但不会返回任何值:
>>> d={}
>>> d['name']='Gumby'
>>> d['age']=42
>>> d
{'name': 'Gumby', 'age': 42}
>>> d.clear()
>>> d
{}
clear方法的一个重要应用场景是处理共享字典的场景。如果多个变量指向同一个字典,使用clear()可以确保所有引用该字典的变量都看到字典被清空的效果:
x={}
y=x#y和x指向同一个字典
#在x中添加键值对
x['key']='value'
print(y)
#讲x重新赋值为空字典
x={}
print(x)#输出:{}
print(y)#输出:{‘key':'value'}
上述代码在清空x时,对y没有任何影响。如果要使所有指向该字典的变量都会看到字典被清空的效果,必须使用clear:
x={}
y=x#y和x指向同一个字典
#在x中添加键值对
x['key']='value'
print(y)
#讲x重新赋值为空字典
x.clear()
print(x)#输出:{}
print(y)#输出:{}
方法copy是字典的一个内置方法,用于浅复制字典。浅复制意味着新字典会包含原字典的所有键值对,如果原字典中的值是可变对象(列表、字典等),新字典中对应的值任然是指向同一个对象的引用。示例:
x={
'username':'admin',
'machines':['foo','bar','baz']
}
y=x.copy()#浅复制
print(x)# 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
print(y)# 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
#替换副本中的值
y['username']='mlh'
print(x) # 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
print(y)# 输出: {'username': 'mlh', 'machines': ['foo', 'bar', 'baz']}
#修改嵌套对象(列表)
y['machines'].remove('baz')
print(x)# 输出: {'username': 'admin', 'machines': ['foo', 'baz']}
print(y)# 输出: {'username': 'mlh', 'machines': ['foo', 'baz']}
浅复制的优点是效率高,因为它只是创建了一个新的字典对象,并没有复制嵌套的对象(如列表、字典等)。然而,这也带来了潜在的问题:
为了避免浅复制带来的问题(即修改嵌套对象时原字典也被修改),可以使用深复制(Deep Copy) 。Python的copy模块提供了deepcopy()函数,可以实现深复制。深复制会递归地复制所有嵌套的对象,确保副本和原字典完全独立。
from copy import deepcopy
x={
'username':'admin',
'machines':['foo','bar','baz']
}
y=deepcopy(x)#深复制
print(x)# 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
print(y)# 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
#替换副本中的值
y['username']='mlh'
print(x) # 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
print(y)# 输出: {'username': 'mlh', 'machines': ['foo', 'bar', 'baz']}
#修改嵌套对象(列表)
y['machines'].remove('baz')
print(x)# 输出: {'username': 'admin', 'machines': ['foo', 'bar', 'baz']}
print(y)# 输出: {'username': 'mlh', 'machines': ['foo', 'baz']}
fromkeys方法创建一个新字典,其中包含指定的键,且每个键的值都是None。如果不想使用默认的None,可以提供特定的值。fromkeys的基本语法是:
{}.fromkeys(keys)
参数keys是一个可迭代的对象(如列表、元组等),包含要作为键的元素。示例:
keys=['name','age']
result={}.fromkeys(keys)
print(result)#输出 :{'name': None, 'age': None}
上述代码创建一个空字典后调用fromkeys,也可以通过dict调用:
print(dict.fromkeys(['name','age']))#输出:{'name': None, 'age': None}
如果希望为所有键设置同一个自定义值,可以提供第二个参数:
{}.fromkeys(keys,value)
示例:
keys=['name','age']
result={}.fromkeys(keys,'(unknown)')
print(result)#输出{'name': '(unknown)', 'age': '(unknown)'}
get是字典的一个非常重要的方法,相比直接通过d[key]访问字典,get方法提供了更友好的错误处理机制。
get的基本语法是
d.get(key,default=None)
key是要查找的键,default可选,如果键不存在时返回None,如果键存在则返回对应值。示例:
d={}
#尝试直接访问不存在的键
print(d['name'])#报错:KeyError: 'name'
#使用get安全访问
print(d.get('name'))#输出:None
#指定默认值
print(d.get('name','N/A'))#输出 N/A
如果字典中存在指定的键,get的行为与直接访问一致:
d={'name':'Eric'}
#使用get安全访问
print(d.get('name'))#输出:Eric
#指定默认值,但是键存在,会被忽略
print(d.get('name','N/A'))#输出:Eric
people = {
'Alice': {'phone': '123-456-7890', 'addr': '123 Main St'},
'Bob': {'phone': '987-654-3210', 'addr': '456 Elm St'}
}
#定义标签映射,用于将简写转换为完整名称
labels={
'phone':'phone number',
'addr':'address'
}
#获取用户输入的姓名
name=input('Name: ')
#获取用户想要查询的内容类型:电话号码(p)或地址(a)
request = input('Phone number (p) or address (a)?')
#确定正确的键
key = request
if request =='p':
key = 'phone'
elif request == 'a':
key = 'addr'
#使用get()提供默认值
person = people.get(name,{})#从people字典中获取指定姓名的联系人信息,如果不存在则返回空字典
label = labels.get(key,key)#从字典中获取完整键名,若不存在则返回原键名
result = person.get(key,'not available')#从person字典中获取指定键值,如不存在则返回‘not available“
#输出结果
print("{}'s {} is {}.".format(name,label,result))
items方法返回一个包含所有字典项的列表,其中每个元素都为(key,value)的形式。字典项在列表中的顺序不确定,取决于底层字典的实现:
d={'title':'python web site','url':'http:python.org','spam':0}
print(d.items())#输出:dict_items([('title', 'python web site'), ('url', 'http:python.org'), ('spam', 0)])
返回值属于一种名为字典视图的特殊类型。字典视图本身是只读的,不能直接对其进行修改,支持迭代和成员资格检查(len()、in等):
d={'title':'python web site','url':'http:python.org','spam':0}
print(d.items())#输出:dict_items([('title', 'python web site'), ('url', 'http:python.org'), ('spam', 0)])
it=d.items()
print(len(it))#输出3
print(('spam',0) in it)#输出True
视图的另一个优点是不复制,它们始终是底层字典的反映,当修改底层字典时,视图会自动更新:
it = d.items()
print(len(it)) # 输出: 3
print(('spam', 0) in it) # 输出: True
# 修改底层字典
d['spam'] = 1
print(('spam', 0) in it) # 输出: False
print(('spam', 1) in it) # 输出: True
如果要将字典视图转换为列表,可以使用list()函数:
print(list(d.items())) # 输出: [('title', 'Python Web Site'), ('url', 'http://www.python.org'), ('spam', 0)]
keys方法返回一个包含字典中的所有键的字典视图:
print(d.keys()) # 输出: dict_keys(['title', 'url', 'spam'])
与items相同,keys视图也是底层字典的实时反映,也支持迭代和成员检查。
pop方法可用于获取指定键的关联值,并将该键值对从字典删除。如果指定的键不存在,可以提供一个默认值;如果键不存在且未提供默认值,则抛出KeyError错误:
d={'x':1,'y':2}
print(d.pop('x'))#输出 1
print(d)#输出 {'y': 2}
#处理键不存在的情况
print(d.pop('z', 'default_value')) # 输出: 'default_value'
print(d) # 输出: {'x': 1, 'y': 2}
如果当前字典不为空,popitem方法随机弹出一个键值对 (即删除并返回一个键值对);如果字典为空,抛出KeyError错误:
d = {'url': 'http://www.python.org', 'spam': 0, 'title': 'Python Web Site'}
print(d.popitem()) # 输出: ('url', 'http://www.python.org')
print(d) # 输出: {'spam': 0, 'title': 'Python Web Site'}
由于字典是无序的,所以popitem方法弹出的键值对也是随机的,即字典没有像列表一样”最后一个元素“的概念 。如果希望以可预测的顺序弹出键值对,可以使用collections模块中的OrderedDict类,它保留插入顺序。
setdefault是字典的一个方法,用于获取指定键对应的值 ,如果键不存在,则在字典中添加该键并设置默认值None:
d={}
print(d.setdefault('name','N/A'))#输出N/A
print(d)#输出{'name': 'N/A'}
#修改默认值
d['name']='Gumdy'
print(d.setdefault('name','New Default'))#输出 Gumdy
print(d)#输出{'name': 'Gumdy'}
get和setdefault方法都可以获取值,但是get不会修改字典,而setdefault会在键不存在时添加默认值。
update方法用于更新字典的内容 。它可以将另一个字典或键值对序列中的内容合并到当前字典中,如果当前字典中已经存在相同的键,则替换其值。
d={'title':'python web site','url':'http:python.org','changed':'mar14 22:09:15 MET 2016'}
x={'title':'python language website'}
d.update(x)
print(d) # 输出: {'title': 'python language website', 'url': 'http:python.org', 'changed': 'mar14 22:09:15 MET 2016'}
update方法支持多种形式的输入:
#字典
d.update({'new_key':'new_value'})
#键值对序列
d.update([('new_key','new_value')])
#关键字序列
d.update(new_key='new_value')
values方法用于返回一个包含所有值的字典视图,顺序不确定。
d={1:1,2:2,3:3,4:1}
print(d.values())# 输出: dict_values([1, 2, 3, 1])
不同于方法keys,方法values返回的视图可能包含重复的值,因为字典允许不同的键对应相同的值。
要遍历字典的所有关键字,可像遍历序列那样使用普通的for语句。
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(key)
输出:
x
y
z
如果需要访问对应的值,可以通过 d[key]
获取。
d = {'x': 1, 'y': 2, 'z': 3}
for key in d:
print(f"{key} corresponds {d[key]}")
如果只想遍历字典的值,可以使用values()方法
d = {'x': 1, 'y': 2, 'z': 3}
for value in d.values():
print(value)
如果需要同时获取键和值,可以使用 items()
方法。items()
返回一个包含键值对的视图对象,每个键值对是一个元组 (key, value)
。
d = {'x': 1, 'y': 2, 'z': 3}
for key, value in d.items():
print(f"{key} corresponds to {value}")