第6章 字典

发布于 2022-03-07  129 次阅读


本章学习能够将相关信息关联起来的Python字典,以及如何访问和修改字典中的信息。字典可存储的信息量几乎不受限制。
如何遍历字典中的数据,另外学习存储字典的列表,存储列表的字典和存储字典的字典。
理解字典后,就能够准确更准确的为各种真实物体建模。例如:可以创建一个表示人的字典,然后再其中存储多少信息就存储多少信息:姓名、年龄、地址、职业,以及能描述他的任何方面。你还能够存储任意两种相关的信息。如一些列单词及其含义,一系列人名及其喜欢的数,以及一系列山脉及其海拔等等。

6.1 一个简单的字典

一个包含外星人的游戏,这些外星人的颜色和分数各不相同。下面是一个简单的字典,存储了有关特定外星人的信息:

# olien.py
alien_0 = {'color':'green','points':5}

print(aline_0['color'])
print(aline_0['point'])

file

6.2 使用字典

在Python中,字典是一系列键值对。每个键都与一个值相关联,可以使用键来访问相关联的值。与键相关联的值可以是数、字符串、列表乃至字典。事实上,可将任何Python对象用作字典中的值。
在Python中,字典用放在花括号({})中的一系列键值对表示。
键值对是两个相关联的值。指定键时,Python将返回与之相关联的值。键和值之间用冒号分隔,而键值对之间用逗号分隔,在字典中,想存储多少个键值都可以。
最简单的字典就是只有一个键值对:

aline_0 = {'color':'green'}

6.2.1 访问字典中的值

要获取与键相关联的值,可依次指定字典名和放在方括号内的键:

# olien.py
alien_0 = {'color':'green'}
print(alien_0['color'])

将返回字典中alien_0中与键'color'相关联的值:
green
字典中可包含任意数量的键值对。
现在你可以访问外星人aline_0的颜色和分数。如果玩家射杀了这个外星人,就可以使用下面的代码来确定应获得多少分:

alien_0 = {'color':'green','points':5}

new_points = alien_0['points']
print(f"You just earned {new_points} points!")

file

6.2.2 添加键值对

字典是一种动态,可随时在其中添加键值对。要添加键值对,可依次指定字典名、用方括号括起的键和相关联的值。
下面在字典中添加两项信息:外星人的x坐标和y坐标表,让我们能够在屏幕的特定位置显示该外星人。
将这个外星人放在屏幕左边缘,且距离顶部25像素的地方。由于屏幕坐标系的原点通常为左上角,要将该外星人放在屏幕左边缘,可将x坐标设置为0;要将该外星人放在离屏幕顶部25像素的地方,可将y坐标设置为25,如下:

# alien3.py
alien_0 = {'color':'green','points':5}
print(alien_0)

alien_0['x_position'] = 0
alien_0['y_position'] = 25
print(alien_0)

file
首先定义前面一直在使用的字典,然后打印这个字典。以显示其信息快照。
这个字典最终包含四个键值对。

在Python3.7中,字典中元素的排列顺序与定义时相同。如果将字典打印出来或遍历其元素,将发现元素的排列顺序与添加顺序相同。

6.2.3 先创建一个空字典

在空字典中添加键值对有时候可提供便利,而有时候必须这样做。为此,可先使用一对花括号定义一个字典,再分行添加各个键值对。例如:

# alien.py
alien_0 = {}

alien_0['color'] = 'green'
alien_0['points'] = 5

print(alien_0)

使用空字典来存储用户提供的数据或再编写能自动生成大量键值对的代码时,通常需要先定义一个空字典。

6.2.4 修改字典中的值

要修改字典中的值,可依次指定字典名、用方括号括起来的键,以及与该键相关联的新值。例如:假设随着游戏的进行,需要将一个外星人从绿色变为黄色:

# alinen4.py
alien_0 = {'color':'green'}
print(f"The alien is {alien_0['color']}.")

alien_0['color'] = 'yellow'
print(f"The alien is now{alien_0['color']}")

file

对一个能够以不同速度移动的外星人进行位置跟踪,为此,存储该外星人的当前速度,并以此确定该外星人将向右移动多远。

# alien5.py
alien_0 = {'x_position':0,'y_position':25,'speed':'medium'}
print(f"Original x_position:{alien_0['x_position']}")

# 向右移动外星人
# 根据当前速度确定外星人向右移动的速度
if alien_0['speed'] == 'slow':
    x_increment = 1
elif alien_0['speed'] == 'medium':
    x_increment = 2
else:
    x_increment = 3
# 新位置为旧位置加上移动距离
alien_0['x_position'] = alien_0['x_position'] + x_increment

print(f"New x_position:{alien_0['x_position']}")

file

6.2.5 删除键值对

对于字典中不再需要的信息,可以使用del语句将相应的键值对彻底删除。使用del语句时,必须指定字典名和要删除的键。

alien = {'color':'green','points':5}
print(alien_0)

del alien_0['points']
print(alien_0)

file
注意:删除的键值会永远消失。

6.2.6 由类似对象组成的字典

可以使用字典来存储众多对象的同一种信息。例如,假设你要调查很多人,询问最喜欢的编程语言:

favorite_languages = {
    'jen':'python',
    'sarah':'c',
    'edward':'ruby',
    'phil':'python',
}

一种不错的做法是,在最后一个键值对后面加上一个逗号,为以后在下一行添加键值对做好准备。

对于较长的列表和字段,大多数编辑器提供了以类似方法设置格式的功能。

给定被调查者的名字,可使用这个字典轻松的获悉他喜欢的语言:

# favorite_languages.py
favorite_languages = {
    'jen':'python',
    'sarah':'c',
    'edward':'ruby',
    'phil':'python',
}

language = favorite_languages['sarah'].title()
print(f"Sarah's favorite language is {language}.")

file

6.2.7 使用get()来访问值

使用放在方括号内的键从字典中获取感兴趣的值时,可能会引发问题,如果指定的键不存在就会出错。
file
就字典而言,可以使用方法get()在指定键不存在时返回一个默认值,从而避免这样的错误。
方法get()的第一个参数用于指定键,是必不可少的,第二个参数为指定的键不存在时要返回的值,是可选的。

alien_0 = {'color':'green','speed':'slow'}

point_value = alien_0.get('points','No point value assigned.')
print(point_value)

file
如果字典中有键'points',将获得与之相关联的值;如果没有。将获得指定的默认值。且不会引发向前面那种错误。
如果指定的键有可能不存在,应考虑使用方法get(),而不要使用方括号表示法。
注意:调用get()时候,如果没有指定第二个参数且指定的键不存在时,Python将返回None。这个值表示没有相应的值。None不是错误,而是一个表示所需值不存在的特殊值。
file

6.3 遍历字典

一个Python字典可能只包含几个键值对。也可能包含数百万个键值对。鉴于字典可能包含大量的数据,Python支持对字典进行遍历。字典可用于各种方式的存储信息,因此有多种遍历方式:可遍历字典的所有键值对,也可遍历键或值。

6.3.1 遍历所有的键值对

探索各种遍历方法前,先来看一个新字典,它用于存储有关网站用户的信息。下面的字典存储了一名用户的的用户的用户名、名和姓:

user_0 = {
    'username': 'efermi',
    'first': 'enrico',
    'last':'gerni',
}

for key,value in user_0.items():
    print(f"\nKey:{key}")
    print(f"Value:{value}")

file

要编写遍历字典的for循环,可声明两个变量,用于存储键值对对中的键和值。这两个变量可以使用任意名称,下面的代码使用了简单的变量名,这完全可行:

for k, v in user_0.item()

for语句的第二部分包含字典名和方法items(),它返回一个键值对列表。接下来,for循环依次将每个键值对赋值给指定的两个变量。在本例中,使用这两个变量来打印每个键及其相关的值。
在6.2.6节的示例favorite_languages.py中,字典存储的是不同人的同一种信息。对于类似这样的字典,遍历所有的键值对很合适。如果遍历字典favorite_languages,将得到其中每个人的姓名和喜欢的编程语言,由于该字典中的键都是人名,值都是语言,因此在循环中使用变量name和language,而不是key和value。

favorite_languages = {
        'jen':'python',
        'sarah':'c',
        'edward':'ruby',
        'phil':'python',
        }

language = favorite_languages['sarah'].title()
print(f"Sarah's favorite language is {language}.")
for name, language in favorite_languages.items():
    print(f"{name.title()}'s favorite language is {language.title()}.")

file

即便使用字典存储的是成千乃至上百万人的调查结果,这种循环也管用。

6.3.2 遍历字典中的所有键

在不需要使用字典中的值时,方法keys()很有用。下面来遍历字典favorite_languages。

...
for name in favorite languages.keys():
    print(f"{name.title()}")

file

遍历字典时,会默认遍历所有的键。

for name in favorite languages.keys():
# 等价
for name in favorite languages:

显式地使用方法keys()可让代码更容易理解。
在这种循环中,可使用当前键来访问与之相关联的值。

favorite_languages = {
        'jen':'python',
        'sarah':'c',
        'edward':'ruby',
        'phil':'python',
        }

# language = favorite_languages['sarah'].title()
# print(f"Sarah's favorite language is {language}.")
# for name, language in favorite_languages.items():
#     print(f"{name.title()}'s favorite language is {language.title()}.")
# for name in favorite_languages.keys():
#     print(f"{name.title()}")
friends = ['phil','sarah']
for name in favorite_languages.keys():
    print(f"Hi {name.title()}")

    if name in friends:
        language = favorite_languages[name].title()
        print(f"\t{name.title()},I see you love {language}")

file
还可以使用方法keys()来确认某个人是否接受了调查;

...
if 'erin' not in favorite_languages.key():
    print("Erin,please take our poll!")

file
方法keys()并非只能用用于遍历:实际上,它返回一个列表,其中包含字典中的所有键。
file

6.3.3 按特定顺序遍历字典中的所有键

从Python3.7开始,遍历字典时将按插入的顺序返回其中的元素。
要以特定顺序返回元素,一种方法是直再for循环中对返回的键进行排序。为此,可使用函数sorted()来获得特定顺序排列的键列表的副本:

...
for name in sorted(favorite_languages.keys()):
    print(f"{name.title()}")

file

6.3.4 遍历字典中的所有值

如果只是对字典中的值感兴趣,那么使用values()

...
for language in favorite_languages.values():
    print(f"{language}")

file
这样的做法是提取字典中的所有值,而没有考虑是否重复,当调查者很多时,最终的列表可能包含大量的重复项。为了剔除,可使用集合(set).集合中的每个元素都是独一无二的:

...
for language in set(favorite_languages.value):
    print(language.title())

file

注意:
可以使用一堆花括号直接创建集合,并在其中用逗号分隔元素:
>>> languages = {'C','PYTHON','C'}
>>> languages
{'C','PYTHON'}
与字典不同的是,集合不会以特定的顺序存储元素。

6.4 嵌套

有时候,需要将一系列字典存储在列表中,或将列表作为值存储在字典中,这称为嵌套。
可以在列表中嵌套字典、在字典中嵌套列表甚至在字典中嵌套字典。

6.4.1 字典列表

字典alien_0包含一个外星人的各种信息,但无法存储第二个外星人的信息。如何管理成群的外星人呢?一个办法是创建一个外星人列表,其中每个外星人都是一个字典,包含有关该外星人的各种信息。例如:

# aliens.py
alien_0 = {'color':'green','points':5}
alien_1 = {'color':'yellow','points':10}
alien_2 = {'color':'red','points':15}

aliens = [alien_0,alien_1,alien_2]
for alien in aliens:
    print(alien)

file

更符合现实的情形是,外星人不止三个,且每个外星人都是使用代码自动生成的。

# alien_range
aliens = [];
for alien_number in range(30):
    new_alien = {'color':'green','points':5,'speed':'slow'}
    aliens.append(new_alien)

# 显示前面五个外星人
for alien in aliens[:5]:
    print(alien)

print(f"Total number of aliens:{len(aliens)}")

file

# alien_range
aliens = [];
for alien_number in range(30):
    new_alien = {'color':'green','points':5,'speed':'slow'}
    aliens.append(new_alien)

for alien in aliens[:3]:
    if alien['color'] == 'green':
        alien['color'] = 'yellow'
        alien['points'] = 10
        alien['speed'] = 'medium'

# 显示前面五个外星人
for alien in aliens[:5]:
    print(alien)
print("..")
# print(f"Total number of aliens:{len(aliens)}")

file

经常需要在列表中包含大量的字典,而其中每个字典都包含特定对象的众多信息。例如,你可能需要为网站的每个用户创建一个字典,并将这些字典存储在一个名为users的列表中,在这个列表中,所有字典的结构都相同,因此你可以遍历这个列表,并以相同的方式处理其中的每个字典。

6.4.2 在字典中存储列表

有时候,需要将列表存储在字典中,而不是将字典存储在列表中。
例如,你如何描述顾客点的披萨呢?如果使用列表,只能存储要添加的比萨配料,但如果使用字典,就不仅可在其中包含配料列表,还可以包含其他有关比萨的描述。

# pizza.py
pizza = {
        'crust':'thick',
        'toppings':['mushrooms','extra cheese'],
        }
# 概述所点的比萨
print(f"You ordered a {pizza['crust']}-crust pizza"
        "with the folloing toppings:")

for topping in pizza['toppings']:
    print("\t"+topping)

file
每当需要在字典中将一个键关联到多个值时,都可以在字典中嵌套一个列表。

# favorite_languages.py
favorite_languages = {
        'jen':['python','ruby'],
        'sarah':['c'],
        'edward':['ruby','go'],
        'phil':['python','haskell']
        }
for name,languages in favorite_languages.items():
    print(f"\n{name.title()}'s favorite languages are:")
    for language in languages:
        print(f"\t{language.title()}")

file
可以进一步修改,if语句检查长度是否为1,单独隔离。

注意:列表和字典的嵌套不宜太多,如果嵌套层级比前面的示例多得多,很可能有更简单的解决方案。

6.4.3 在字典中存储字典

可在字典中嵌套字典,但这样做时,代码可能很快复杂起来了。例如,有多个网站用户,每个都有独特的用户名,可在字典中将用户名作为键,然后将每个用户的信息存储在一个字典中,并将该字典作为与用户名相关联的值。

# many_users.py
users = {
        'aeinstein':{
            'first':'albert',
            'last':'einstein',
            'location':'princeton',
            },
        'mcurie':{
            'first':'marie',
            'last':'curie',
            'location':'paris',
            },
        }
for username,user_info in users.items():
    print(f"\nUserName:{username}")
    full_name = f"{user_info['first']} {user_info['last']}"
    location = user_info['location']

    print(f"\t Full name:{full_name.title()}")
    print(f"\t Location:{location}")

file
表示美味用户的字典都具有相同的结构,虽然Python并没有这样的要求,但这使得嵌套的字典处理起来更容易,倘若表示每位用户的字典都包含不同的键,for循环内部的代码将更复杂。

6.5 小结

如何定义字典,如何使用存储在字典中的信息。如何访问和修改字典中的元素,以及如何遍历字典中的所有信息;如何遍历字典中所有的键值对、所有键和所有的值;如何在列表中嵌入字典、在字典中嵌套列表以及字典中嵌套字典。


擦肩而过的概率