本文参考《Python 编程:从入门到实践》一书,作者:[ 美 ] Eric Matthes
第1章 起步
1.1 搭建python环境
在不同的操作系统中, Python 存在细微的差别。
1.1.1 Python 2和Python 3
在本书中,将指出 Python 2 和 Python 3 的重大差别。
1.1.2 运行Python代码片段
1.1.3 Hello World程序
长期以来,编程界都认为刚接触一门新语言时,如果首先使用它来编写一个在屏幕上显示消息“Hello World!”的程序,将给你带来好运。
只需一行代码:
print("Hello World!")
1.2 在不同操作系统中搭建 Python 编程环境
Python 是一种跨平台的编程语言,这意味着它能够运行在所有主要的操作系统中。在所有安装了 Python 的现代计算机上,都能够运行你编写的任何 Python 程序。然而,在不同的操作系统中,安装 Python 的方法存在细微的差别。
1.2.1 在 Linux 系统中搭建 Python 编程环境
1. 检查 Python 版本
2. 安装文本编辑器
Geany 是一款简单的文本编辑器:它易于安装;让你能够直接运行几乎所有的程序(而无需通过终端来运行);使用不同的颜色来显示代码,以突出代码语法;在终端窗口中运行代码,让你能够习惯使用终端。
3. 运行 Hello World 程序
4. 在终端会话中运行 Python 代码
1.2.2 在 OS X 系统中搭建 Python 编程环境
1. 检查是否安装了 Python
1.2.3 在 Windows 系统中搭建 Python 编程环境
Windows 系统并非都默认安装了 Python ,因此你可能需要下载并安装它,再下载并安装一个文本编辑器。
1. 安装 Python
2. 启动 Python 终端会话
3. 在终端会话中运行 Python
4. 安装文本编辑器
Geany 是一款简单的文本编辑器:它易于安装;让你能够直接运行几乎所有的程序(而无需通过终端);使用不同的颜色来显示代码,以突出代码语法;在终端窗口中运行代码,让你能够习惯使用终端。
5. 配置 Geany
6. 运行 Hello World 程序
1.3 解决安装问题
1.4 从终端运行 Python 程序
1.4.1 在 Linux 和 OS X 系统中从终端运行 Python 程序
1.4.2 在 Windows 系统中从终端运行 Python 程序
第 2 章 变量和简单数据类型
在本章中,你将学习可在 Python 程序中使用的各种数据,还将学习如何将数据存储到变量中,以及如何在程序中使用这些变量。
2.1 运行 hello_world.py 时发生的情况
运行 hello_world.py 时, Python 都做了些什么呢?下面来深入研究一下。实际上,即便是运行简单的程序,Python 所做的工作也相当多:
运行文件 hello_world.py 时,末尾的 .py 指出这是一个 Python 程序,因此编辑器将使用 Python 解释器 来运行它。 Python 解释器读取整个程序,确定其中每个单词的含义。例如,看到单词 print 时,解释器就会将括号中的内容打印到屏幕,而不会管括号中的内容是什么。
编写程序时,编辑器会以各种方式突出程序的不同部分。例如,它知道 print 是一个函数的名称,因此将其显示为蓝色;它知道 “Hello Python world!” 不是 Python 代码,因此将其显示为橙色。这种功能称为 语法突出 ,在你刚开始编写程序时很有帮助。
2.2 变量
2.2.1 变量的命名和使用
在 Python 中使用变量时,需要遵守一些规则和指南。违反这些规则将引发错误,而指南旨在让你编写的代码更容易阅读和理解。请务必牢记下述有关变量的规则。
变量名只能包含字母、数字和下划线。变量名可以字母或下划线打头,但不能以数字打头,例如,可将变量命名为 message_1 ,但不能将其命名为 1_message 。
变量名不能包含空格,但可使用下划线来分隔其中的单词。例如,变量名 greeting_message 可行,但变量名 greeting message 会引发错误。
不要将 Python 关键字和函数名用作变量名,即不要使用 Python 保留用于特殊用途的单词,如 print (请参见附录 A.4 )。
变量名应既简短又具有描述性。例如, name 比 n 好, student_name 比 s_n 好, name_length 比 length_of_persons_name 好。
慎用小写字母l 和大写字母O ,因为它们可能被人错看成数字 1 和 0 。
要创建良好的变量名,需要经过一定的实践,在程序复杂而有趣时尤其如此。随着你编写的程序越来越多,并开始阅读别人编写的代码,将越来越善于创建有意义的变量名。
注意:就目前而言,应使用小写的 Python 变量名。在变量名中使用大写字母虽然不会导致错误,但避免使用大写字母是个不错的主意。
2.2.2 使用变量时避免命名错误
我们将有意地编写一些引发错误的代码。请输入下面的代码,包括其中拼写不正确的单词 mesage :
程序存在错误时, Python 解释器将竭尽所能地帮助你找出问题所在。程序无法成功地运行时,解释器会提供一个traceback 。 traceback 是一条记录,指出了解释器尝试运行代码时,
在什么地方陷入了困境。下面是你不小心错误地拼写了变量名时, Python 解释器提供的 traceback :
解释器指出,文件 hello_world.py 的第 2 行存在错误(见❶);
它列出了这行代码,旨在帮助你快速找出错误(见❷);
它还指出了它发现的是什么样的错误(见❸)。在这里,解释器发现了一个名称错误,并指出打印的变量 mesage 未定义: Python 无法识别你提供的变量名。名称错误通常意味着两种情况:要么是使用变量前忘记了给它赋值,要么是输入变量名时拼写不正确。
Python 解释器不会对代码做拼写检查,但要求变量名的拼写一致。
很多编程错误都很简单,只是在程序的某一行输错了一个字符。为找出这种错误而花费很长时间的大有人在。很多程序员天资聪颖、经验丰富,却为找出这种细微的错误花费数小时。你可能觉得这很好笑,但别忘了,在你的编程生涯中,经常会有同样的遭遇。
注意:要理解新的编程概念,最佳的方式是尝试在程序中使用它们。如果你在做本书的练习时陷入了困境,请尝试做点其他的事情。如果这样做后依然无法摆脱困
境,请复习相关内容。如果这样做后情况依然如故,请参阅附录 C 的建议。
2.3 字符串
字符串虽然看似简单,但能够以很多不同的方式使用它们。
字符串 就是一系列字符。在 Python 中,用引号括起的都是字符串,其中的引号可以是单引号,也可以是双引号,如下所示:
这种灵活性让你能够在字符串中包含引号和撇号:
2.3.1 使用方法修改字符串的大小写
输出如下:
在这个示例中,小写的字符串 "ada lovelace" 存储到了变量 name 中。
在 print() 语句中,方法 title() 出现在这个变量的后面。
方法 是 Python 可对数据执行的操作。
每个方法后面都跟着一对括号,这是因为方法通常需要额外的信息来完成其工作。这种信息是在括号内提供的。
函数 title() 不需要额外的信息,因此它后面的括号是空的。
title() 以首字母大写的方式显示每个单词,即将每个单词的首字母都改为大写。这很有用!
还有其他几个很有用的大小写处理方法。例如,要将字符串改为全部大写或全部小写:
输出如下:
存储数据时,方法 lower() 很有用。很多时候,你无法依靠用户来提供正确的大小写,因此需要将字符串先转换为小写,再存储它们。以后需要显示这些信息时,再将其转换为最合适的大小写方式。
2.3.2 合并(拼接)字符串
Python 使用加号( + )来合并字符串。这种合并字符串的方法称为拼接 。通过拼接,可使用存储在变量中的信息来创建完整的消息。
在这里,一个问候用户的句子中使用了全名(见❶),并使用了方法 title() 来将姓名设置为合适的格式。这些代码显示一条格式良好的简单问候语:
你可以使用拼接来创建消息,再把整条消息都存储在一个变量中:
这让最后的 print 语句简单得多(见❷)。
2.3.3 使用制表符或换行符来添加空白
在编程中, 空白泛指任何非打印字符,如空格、制表符和换行符。你可使用空白来组织输出,以使其更易读。
要在字符串中添加制表符,可使用字符组合
要在字符串中添加换行符,可使用字符组合 (这个就太熟悉了有木有^_^)
还可在同一个字符串中同时包含制表符和换行符。字符串 " " 让 Python 换到下一行,并在下一行开头添加一个制表符。
2.3.4 删除空白
在程序中,额外的空白可能令人迷惑。对程序员来说, 'python' 和 'python ' 看起来几乎没什么两样,但对程序来说,它们却是两个不同的字符串。 Python 能够发现 'python ' 中额外的空白,并认为它是有意义的 —— 除非你告诉它不是这样的。
空白很重要,因为你经常需要比较两个字符串是否相同。例如,一个重要的示例是,在用户登录网站时检查其用户名。但在一些简单得多的情形下,额外的空格也可能令人迷惑。所幸在 Python 中,删除用户输入的数据中的多余的空白易如反掌。
Python 能够找出字符串开头和末尾多余的空白。要确保字符串末尾没有空白,可使用方法 rstrip() 。
对变量 favorite_language 调用方法 rstrip() 后(见❸),这个多余的空格被删除了。然而,这种删除只是暂时的,接下来再次询问 favorite_language 的值时,你会发现这个字符串与输入时一样,依然包含多余的空白(见❹)。
要永久删除这个字符串中的空白,必须将删除操作的结果存回到变量中:
在编程中,经常需要修改变量的值,再将新值存回到原来的变量中。这就是变量的值可能随程序的运行或用户输入数据而发生变化的原因。
还可以剔除字符串开头的空白,或同时剔除字符串两端的空白。为此,可分别使用方法 lstrip() 和rstrip() :
在实际程序中,这些剥除函数最常用于在存储用户输入前对其进行清理。
2.3.5 使用字符串时避免语法错误
注意:编写程序时,编辑器的语法突出功能可帮助你快速找出某些语法错误。看到 Python 代码以普通句子的颜色显示,或者普通句子以 Python 代码的颜色显示时,就可能意味着文件中存在引号不匹配的情况。
2.3.6 Python 2 中的 print 语句
在Python 2 中,无需将要打印的内容放在括号内。从技术上说, Python 3 中的print 是一个函数,因此括号必不可少。有些 Python 2 print 语句也包含括号,但其行为与 Python 3 中稍有不同。简单地说,在 Python 2 代码中,有些 print 语句包含括号,有些不包含。
2.4 数字
在编程中,经常使用数字来记录游戏得分、表示可视化数据、存储 Web 应用信息等。
2.4.1 整数
在 Python 中,可对整数执行加( + )减( - )乘( * )除( / )运算。
Python 使用两个乘号(**)表示乘方运算:
2.4.2 浮点数
浮点数 。大多数编程语言都使用了这个术语,它指出了这样一个事实:小数点可出现在数字的任何位置(浮点,即浮动的点)。
2.4.3 使用函数 str() 避免类型错误、
你可能认为,上述代码会打印一条简单的生日祝福语: Happy 23rd birthday! 。但如果你运行这些代码,将发现它们会引发错误:
这是一个 类型错误 ,意味着 Python 无法识别你使用的信息。在这个示例中, Python 发现你使用了一个值为整数( int )的变量,但它不知道该如何解读这个值(见❶)。 Python 知
道,这个变量表示的可能是数值 23 ,也可能是字符 2 和 3 。像上面这样在字符串中使用整数时,需要显式地指出你希望 Python 将这个整数用作字符串。为此,可调用函数 str() ,
它让 Python 将非字符串值表示为字符串:
这样, Python 就知道你要将数值 23 转换为字符串,进而在生日祝福消息中显示字符 2 和 3 。经过上述处理后,将显示你期望的消息,而不会引发错误。
大多数情况下,在 Python 中使用数字都非常简单。如果结果出乎意料,请检查 Python 是否按你期望的方式将数字解读为了数值或字符串。
2.4.4 Python 2 中的整数
在 Python 2 中,将两个整数相除得到的结果稍有不同:
Python 返回的结果为 1 ,而不是 1.5 。在Python 2 中,整数除法的结果只包含整数部分,小数部分被删除。请注意,计算整数结果时,采取的方式不是四舍五入,而是将小数部分直接删除。
在 Python 2 中,若要避免这种情况,务必确保至少有一个操作数为浮点数,这样结果也将为浮点数:
从 Python 3 转而用 Python 2 或从 Python 2 转而用 Python 3 时,这种除法行为常常会令人迷惑。使用或编写同时使用浮点数和整数的代码时,一定要注意这种异常行为。
2.5 注释
在大多数编程语言中,注释都是一项很有用的功能。
2.5.1 如何编写注释
在 Python 中,注释用井号( # )标识。井号后面的内容都会被 Python 解释器忽略。
2.5.2 该编写什么样的注释
编写注释的主要目的是阐述代码要做什么,以及是如何做的。
在开发项目期间,你对各个部分如何协同工作了如指掌,但过段时间后,有些细节你可能不记得了。当然,你总是可以通过研究代码来确定各个部分的工作原理,但通过编写注释,以清晰的自然语言对解决方案进行概述,可节省很多时间。
要成为专业程序员或与其他程序员合作,就必须编写有意义的注释。
你最好从现在开始就在程序中添加描述性注释。作为新手,最值得养成的习惯之一是,在代码中编写清晰、简洁的注释。
如果不确定是否要编写注释,就问问自己,找到合理的解决方案前,是否考虑了多个解决方案。如果答案是肯定的,就编写注释对你的解决方案进行说明吧。相比回过头去再添加注释,删除多余的注释要容易得多。
2.6 Python 之禅
编程语言 Perl 曾在互联网领域长期占据着统治地位,早期的大多数交互式网站使用的都是 Perl 脚本。彼时, “ 解决问题的办法有多个 ” 被 Perl 社区奉为座右铭。这种理念一度深受大家的喜爱,因为这种语言固有的灵活性使得大多数问题都有很多不同的解决之道。在开发项目期间,这种灵活性是可以接受的,但大家最终认识到,过于强调灵活性会导致大型项目难以维护:要通过研究代码搞清楚当时解决复杂问题的人是怎么想的,既困难又麻烦,还会耗费大量的时间。
经验丰富的程序员倡导尽可能避繁就简。 Python 社区的理念都包含在 Tim Peters 撰写的 “Python 之禅 ” 中。要获悉这些有关编写优秀 Python 代码的指导原则,只需在解释器中执行命令import this 。这里不打算赘述整个 “Python 之禅 ” ,而只与大家分享其中的几条原则,让你明白为何它们对 Python 新手来说至关重要。
Python 程序员笃信代码可以编写得漂亮而优雅。编程是要解决问题的,设计良好、高效而漂亮的解决方案都会让程序员心生敬意。随着你对 Python 的认识越来越深入,并使用它来编写越来越多的代码,有一天也许会有人站在你后面惊呼: “ 哇,代码编写得真是漂亮!"
即便是复杂的代码,也要让它易于理解。开发的项目涉及复杂代码时,一定要为这些代码编写有益的注释。
如果让两名 Python 程序员去解决同一个问题,他们提供的解决方案应大致相同。这并不是说编程没有创意空间,而是恰恰相反!然而,大部分编程工作都是使用常见解决方案来解
决简单的小问题,但这些小问题都包含在更庞大、更有创意空间的项目中。在你的程序中,各种具体细节对其他 Python 程序员来说都应易于理解。
你可以将余生都用来学习 Python 和编程的纷繁难懂之处,但这样你什么项目都完不成。不要企图编写完美无缺的代码;先编写行之有效的代码,再决定是对其做进一步改进,还是转而去编写新代码。
第 3 章 列表简介
列表让你能够在一个地方存储成组的信息,其中可以只包含几个元素,也可以包含数百万个元素。列表是新手可直接使用的最强大的 Python 功能之一,它融合了众多重要的编程概念。
3.1 列表是什么
列表 由一系列按特定顺序排列的元素组成。你可以创建包含字母表中所有字母、数字 0~9 或所有家庭成员姓名的列表;也可以将任何东西加入列表中,其中的元素之间可以没有任何关系。
在 Python 中,用方括号( [] )来表示列表,并用逗号来分隔其中的元素。
3.1.1 访问列表元素
列表是有序集合,因此要访问列表的任何元素,只需将该元素的位置或索引告诉 Python 即可。要访问列表元素,可指出列表的名称,再指出元素的索引,并将其放在方括号内。
3.1.2 索引从 0 而不是 1 开始
根据这种简单的计数方式,要访问列表的任何元素,都可将其位置减 1 ,并将结果作为索引。
Python 为访问最后一个列表元素提供了一种特殊语法。通过将索引指定为-1 ,可让 Python 返回最后一个列表元素:
这种约定也适用于其他负数索引,例如,索引-2 返回倒数第二个列表元素,索引-3 返回倒数第三个列表元素,以此类推。
3.1.3 使用列表中的各个值
3.2 修改、添加和删除元素
你创建的大多数列表都将是动态的,这意味着列表创建后,将随着程序的运行增删元素。
3.2.1 修改列表元素
3.2.2 在列表中添加元素
1. 在列表末尾添加元素
使用方法 append() 将元素 添加到列表末尾。
方法 append() 让动态地创建列表易如反掌,例如,你可以先创建一个空列表,再使用一系列的 append() 语句添加元素。下面来创建一个空列表,再在其中添加元素 'honda' 、 'yamaha' 和 'suzuki' :
这种创建列表的方式极其常见,因为经常要等程序运行后,你才知道用户要在程序中存储哪些数据。为控制用户,可首先创建一个空列表,用于存储用户将要输入的值,然后将用户提供的每个新值附加到列表中。
2. 在列表中插入元素
使用方法 insert() 可在列表的任何位置添加新元素。为此,你需要指定新元素的索引和值。
这种操作将列表中既有的每个元素都右移一个位置:
3.2.3 从列表中删除元素
1. 使用 del 语句删除元素
如果知道要删除的元素在列表中的位置,可使用 del 语句。
看下结果:
使用 del 可删除任何位置处的列表元素,条件是知道其索引。
使用 del 语句将值从列表中删除后,你就无法再访问它了。
2. 使用方法 pop() 删除元素
有时候,你要将元素从列表中删除,并接着使用它的值。
方法 pop() 可删除列表末尾的元素,并让你能够接着使用它。术语 弹出 ( pop )源自这样的类比:列表就像一个栈,而删除列表末尾的元素相当于弹出栈顶元素。
我们首先定义并打印了列表 motorcycles (见❶)。接下来,我们从这个列表中弹出一个值,并将其存储到变量 popped_motorcycle 中(见❷)。然后我们打印这个列
表,以核实从其中删除了一个值(见❸)。最后,我们打印弹出的值,以证明我们依然能够访问被删除的值(见❹)。
输出表明,列表末尾的值 'suzuki' 已删除,它现在存储在变量 popped_motorcycle 中:
3. 弹出列表中任何位置处的元素
实际上,你可以使用 pop() 来删除列表中任何位置的元素,只需在括号中指定要删除的元素的索引即可。
别忘了,每当你使用 pop() 时,被弹出的元素就不再在列表中了。
如果你不确定该使用 del 语句还是 pop() 方法,下面是一个简单的判断标准:
如果你要从列表中删除一个元素,且不再以任何方式使用它,就使用 del 语句;如果你要在删除元素后还能继续使用它,就使用方法 pop() 。
4. 根据值删除元素
有时候,你不知道要从列表中删除的值所处的位置。如果你只知道要删除的元素的值,可使用方法 remove() 。
使用 remove() 从列表中删除元素时,也可接着使用它的值。
注意 方法 remove() 只删除第一个指定的值。如果要删除的值可能在列表中出现多次,就需要使用循环来判断是否删除了所有这样的值。
3.3 组织列表
在你创建的列表中,元素的排列顺序常常是无法预测的,因为你并非总能控制用户提供数据的顺序。
3.3.1 使用方法 sort() 对列表进行永久性排序
方法 sort() (见❶)永久性地修改了列表元素的排列顺序。现在,汽车是按字母顺序排列的,再也无法恢复到原来的排列顺序:
你还可以按与字母顺序相反的顺序排列列表元素,为此,只需向 sort() 方法传递参数 reverse=True 。
3.3.2 使用函数 sorted() 对列表进行临时排序
要保留列表元素原来的排列顺序,同时以特定的顺序呈现它们,可使用函数 sorted() 。函数 sorted() 让你能够按特定顺序显示列表元素,同时不影响它们在列表中的原始排列顺序。
注意,调用函数 sorted() 后,列表元素的排列顺序并没有变(见❹)。如果你要按与字母顺序相反的顺序显示列表,也可向函数 sorted() 传递参数 reverse=True 。
注意 在并非所有的值都是小写时,按字母顺序排列列表要复杂些。决定排列顺序时,有多种解读大写字母的方式,要指定准确的排列顺序,可能比我们这里所做的要复杂。
3.3.3 倒着打印列表
要反转列表元素的排列顺序,可使用方法 reverse() 。
注意,reverse() 不是指按与字母顺序相反的顺序排列列表元素,而只是反转列表元素的排列顺序。
方法 reverse() 永久性地修改列表元素的排列顺序,但可随时恢复到原来的排列顺序,为此只需对列表再次调用 reverse() 即可。
3.3.4 确定列表的长度
使用函数 len() 可快速获悉列表的长度。
注意 Python 计算列表元素数时从 1 开始,因此确定列表长度时,你应该不会遇到差一错误。
3.4 使用列表时避免索引错误
索引错误意味着 Python 无法理解你指定的索引。程序发生索引错误时,请尝试将你指定的索引减 1 ,然后再次运行程序,看看结果是否正确。
别忘了,每当需要访问最后一个列表元素时,都可使用索引 -1 。这在任何情况下都行之有效,即便你最后一次访问列表后,其长度发生了变化:
注意 发生索引错误却找不到解决办法时,请尝试将列表或其长度打印出来。列表可能与你以为的截然不同,在程序对其进行了动态处理时尤其如此。通过查看列表或其包含的元素数,可帮助你找出这种逻辑错误。
第 4 章 操作列表
在本章中,你将学习如何 遍历 整个列表,这只需要几行代码,无论列表有多长。循环让你能够对列表的每个元素都采取一个或一系列相同的措施,从而高效地处理任何长度的列表,包括包含数千乃至数百万个元素的列表。
4.1 遍历整个列表
需要对列表中的每个元素都执行相同的操作时,可使用 Python 中的for 循环。
我们定义了一个 for 循环(见❷);这行代码让 Python 从列表 magicians 中取出一个名字,并将其存储在变量 magician 中。
最后,我们让 Python 打印前面存储到变量 magician 中的名字(见❸)。
4.1.1 深入地研究循环
循环这种概念很重要,因为它是让计算机自动完成重复工作的常见方式之一。
刚开始使用循环时请牢记,对列表中的每个元素,都将执行循环指定的步骤,而不管列表包含多少个元素。如果列表包含一百万个元素, Python 就重复执行指定的步骤一百万次,且通常速度非常快。
4.1.2 在 for 循环中执行更多的操作
在 for 循环中,可对每个元素执行任何操作。下面来扩展前面的示例,对于每位魔术师,都打印一条消息,指出他的表演太精彩了。
相比于前一个示例,唯一的不同是对于每位魔术师,都打印了一条以其名字为抬头的消息(见❶)。这个循环第一次迭代时,变量 magician 的值为 'alice' ,因此 Python 打印的第一条消息的抬头为 'Alice' 。第二次迭代时,消息的抬头为 'David' ,而第三次迭代时,抬头为 'Carolina' 。
下面的输出表明,对于列表中的每位魔术师,都打印了一条个性化消息:
在 for 循环中,想包含多少行代码都可以。在代码行 for magician in magicians 后面,每个缩进的代码行都是循环的一部分,且将针对列表中的每个值都执行一次。因此,可对列表中的每个值执行任意次数的操作。
由于两条 print 语句都缩进了,因此它们都将针对列表中的每位魔术师执行一次。第二条 print 语句中的换行符 " " (见❶)在每次迭代结束后都插入一个空行,从而整洁地将针对各位魔术师的消息编组:
4.1.3 在 for 循环结束后执行一些操作
4.2 避免缩进错误
4.2.1 忘记缩进
对于位于 for 语句后面且属于循环组成部分的代码行,一定要缩进。如果你忘记缩进, Python 会提醒你:
print 语句(见❶)应缩进却没有缩进。 Python 没有找到期望缩进的代码块时,会让你知道哪行代码有问题。
4.2.2 忘记缩进额外的代码行
4.2.3 不必要的缩进
4.2.4 循环后不必要的缩进
4.2.5 遗漏了冒号
4.3 创建数值列表
列表非常适合用于存储数字集合,而 Python 提供了很多工具,可帮助你高效地处理数字列表。明白如何有效地使用这些工具后,即便列表包含数百万个元素,你编写的代码也能运行得很好。
4.3.1 使用函数 range()
Python 函数 range() 让你能够轻松地生成一系列的数字。
在这个示例中, range() 只是打印数字 1~4 ,这是你在编程语言中经常看到的差一行为的结果。函数 range() 让 Python 从你指定的第一个值开始数,并在到达你指定的第二个值后停止,因此输出不包含第二个值(这里为 5 )。
4.3.2 使用 range() 创建数字列表
要创建数字列表,可使用函数 list() 将 range() 的结果直接转换为列表。如果将 range() 作为 list() 的参数,输出将为一个数字列表。
使用函数 range() 时,还可指定步长。
在这个示例中,函数 range() 从 2 开始数,然后不断地加 2 ,直到达到或超过终值( 11 ),因此输出如下:
使用函数 range() 几乎能够创建任何需要的数字集,例如,如何创建一个列表,其中包含前 10 个整数(即 1~10 )的平方呢?在 Python 中,两个星号( ** )表示乘方运算。下面的代码演示了如何将前 10 个整数的平方加入到一个列表中:
首先,我们创建了一个空列表(见❶);接下来,使用函数 range() 让 Python 遍历 1~10 的值(见❷)。在循环中,计算当前值的平方,并将结果存储到变量 square 中(见❸)。然后,将新计算得到的平方值附加到列表 squares 末尾(见❹)。最后,循环结束后,打印列表 squares (见❺):
为让这些代码更简洁,可不使用临时变量 square ,而直接将每个计算得到的值附加到列表末尾:
squares=[] for value in range(1,11): square=value**2 squares.append(square) print(squares)
创建更复杂的列表时,可使用上述两种方法中的任何一种。有时候,使用临时变量会让代码更易读;而在其他情况下,这样做只会让代码无谓地变长。你首先应该考虑的是,编写清晰易懂且能完成所需功能的代码;等到审核代码时,再考虑采用更高效的方法。
4.3.3 对数字列表执行简单的统计计算
有几个专门用于处理数字列表的 Python 函数。例如,你可以轻松地找出数字列表的最大值、最小值和总和:
4.3.4 列表解析
前面介绍的生成列表 squares 的方式包含三四行代码,而列表解析让你只需编写一行代码就能生成这样的列表。列表解析将 for 循环和创建新元素的代码合并成一行,并自动附加新元素。
要使用这种语法,首先指定一个描述性的列表名,如 squares ;
然后,指定一个左方括号,并定义一个表达式,用于生成你要存储到列表中的值。在这个示例中,表达式为 value**2 ,它计算平方值。
接下来,编写一个for 循环,用于给表达式提供值,再加上右方括号。在这个示例中, for 循环为 for value in range(1,11) ,它将值1~10 提供给表达式 value**2 。请注意,这里的for 语句末尾没有冒号。
4.4 使用列表的一部分
在本章中,你一直在学习如何处理列表的所有元素。你还可以处理列表的部分元素 ——Python 称之为 切片 。
4.4.1 切片
要创建切片,可指定要使用的第一个元素和最后一个元素的索引。与函数 range() 一样, Python 在到达你指定的第二个索引前面的元素后停止。
如果你没有指定第一个索引, Python 将自动从列表开头开始:
本书前面说过,负数索引返回离列表末尾相应距离的元素,因此你可以输出列表末尾的任何切片。例如,如果你要输出名单上的最后三名队员,可使用切片 players[-3:] :
4.4.2 遍历切片
如果要遍历列表的部分元素,可在 for 循环中使用切片。
4.4.3 复制列表
要复制列表,可创建一个包含整个列表的切片,方法是同时省略起始索引和终止索引( [:] )。这让 Python 创建一个始于第一个元素,终止于最后一个元素的切片,即复制整个列表。
下例演示了在不使用切片的情况下复制列表的情况:
这里将 my_foods 赋给 friend_foods ,而不是将 my_foods 的副本存储到 friend_foods (见❶)。这种语法实际上是让 Python 将新变量 friend_foods 关联到包含在 my_foods 中的列表,因此这两个变量都指向同一个列表。鉴于此,当我们将 'cannoli' 添加到 my_foods 中时,它也将出现在 friend_foods 中;同样,虽然 'icecream' 好像只被加入到了 friend_foods 中,但它也将出现在这两个列表中。
注意 现在暂时不要考虑这个示例中的细节。基本上,当你试图使用列表的副本时,如果结果出乎意料,请确认你像第一个示例那样使用切片复制了列表。
4.5 元组
列表非常适合用于存储在程序运行期间可能变化的数据集。
列表是可以修改的,然而,有时候你需要创建一系列不可修改的元素,元组可以满足这种需求。 Python 将不能修改的值称为 不可变的 ,而不可变的列表被称为元组。
4.5.1 定义元组
元组看起来犹如列表,但使用圆括号而不是方括号来标识。定义元组后,就可以使用索引来访问其元素,就像访问列表元素一样。
例如,如果有一个大小不应改变的矩形,可将其长度和宽度存储在一个元组中,从而确保它们是不能修改的:
❶处的代码试图修改第一个元素的值,导致 Python 返回类型错误消息。由于试图修改元组的操作是被禁止的,因此 Python 指出不能给元组的元素赋值:
4.5.2 遍历元组中的所有值
4.5.3 修改元组变量
虽然不能修改元组的元素,但可以给存储元组的变量赋值。因此,如果要修改前述矩形的尺寸,可重新定义整个元组:
相比于列表,元组是更简单的数据结构。如果需要存储的一组值在程序的整个生命周期内都不变,可使用元组。
4.6 设置代码格式
随着你编写的程序越来越长,有必要了解一些代码格式设置约定。请花时间让你的代码尽可能易于阅读;让代码易于阅读有助于你掌握程序是做什么的,也可以帮助他人理解你编写的代码。
要成为专业程序员,应从现在开始就遵循这些指南,以养成良好的习惯。
4.6.1 格式设置指南
若要提出 Python 语言修改建议,需要编写 Python 改进提案 ( Python Enhancement Proposal , PEP )。PEP 8 是最古老的 PEP 之一,它向 Python 程序员提供了代码格式设置指南。 PEP 8 的篇幅很长,但大都与复杂的编码结构相关。
如果一定要在让代码易于编写和易于阅读之间做出选择, Python 程序员几乎总是会选择后者。
4.6.2 缩进
PEP 8 建议每级缩进都使用四个空格,这既可提高可读性,又留下了足够的多级缩进空间。
在字处理文档中,大家常常使用制表符而不是空格来缩进。
对于字处理文档来说,这样做的效果很好,但混合使用制表符和空格会让 Python 解释器感到迷惑。
每款文本编辑器都提供了一种设置,可将输入的制表符转换为指定数量的空格。
你在编写代码时应该使用制表符键,但一定要对编辑器进行设置,使其在文档中插入空格而不是制表符。
在程序中混合使用制表符和空格可能导致极难解决的问题。如果你混合使用了制表符和空格,可将文件中所有的制表符转换为空格,大多数编辑器都提供了这样的功能。
4.6.3 行长
很多 Python 程序员都建议每行不超过 80 字符。
PEP 8 还建议注释的行长都不超过 72 字符,因为有些工具为大型项目自动生成文档时,会在每行注释开头添加格式化字符。
在学习期间,你不用过多地考虑代码的行长,但别忘了,协作编写程序时,大家几乎都遵守PEP 8 指南。
在大多数编辑器中,都可设置一个视觉标志 —— 通常是一条竖线,让你知道不能越过的界线在什么地方。
注意 附录 B 介绍了如何配置文本编辑器,以使其:在你按制表符键时插入四个空格;显示一条垂直参考线,帮助你遵守行长不能超过 79 字符的约定。
4.6.4 空行
要将程序的不同部分分开,可使用空行。你应该使用空行来组织程序文件,但也不能滥用。
空行不会影响代码的运行,但会影响代码的可读性。 Python 解释器根据水平缩进情况来解读代码,但不关心垂直间距。
请访问 https://python.org/dev/peps/pep-0008/ ,阅读 PEP 8 格式设置指南。当前,这些指南适用的不多,但你可以大致浏览一下。
第 5 章 if 语句
5.1 一个简单示例
5.2 条件测试
每条 if 语句的核心都是一个值为 True 或 False 的表达式,这种表达式被称为条件测试。
5.2.1 检查是否相等
一个等号是陈述;对于❶处的代码,可解读为 “ 将变量 car 的值设置为 'audi' ” 。两个等号是发问;对于❷处的代码,可解读为 “ 变量 car 的值是 'bmw' 吗? ” 。
5.2.2 检查是否相等时不考虑大小写
在Python 中检查是否相等时区分大小写,例如,两个大小写不同的值会被视为不相等:
如果大小写很重要,这种行为有其优点。但如果大小写无关紧要,而只想检查变量的值,可将变量的值转换为小写,再进行比较:
函数 lower() 不会修改存储在变量 car 中的值:
5.2.3 检查是否不相等
要判断两个值是否不等,可结合使用惊叹号和等号(!= ),其中的惊叹号表示 不。
我们将把要求的比萨配料存储在一个变量中,再打印一条消息,指出顾客要求的配料是否是意式小银鱼( anchovies ):
你编写的大多数条件表达式都检查两个值是否相等,但有时候检查两个值是否不等的效率更高。
5.2.4 比较数字
条件语句中可包含各种数学比较,如小于、小于等于、大于、大于等于:
5.2.5 检查多个条件
你可能想同时检查多个条件,例如,有时候你需要在两个条件都为 True 时才执行相应的操作,而有时候你只要求一个条件为 True 时就执行相应的操作。在这些情况下,关键字 and 和 or 可助你一臂之力。
1. 使用 and 检查多个条件
为改善可读性,可将每个测试都分别放在一对括号内,但并非必须这样做。如果你使用括号,测试将类似于下面这样:
2. 使用 or 检查多个条件
关键字 or 也能够让你检查多个条件,但只要至少有一个条件满足,就能通过整个测试。仅当两个测试都没有通过时,使用 or 的表达式才为 False 。
5.2.6 检查特定值是否包含在列表中
有时候,执行操作前必须检查列表是否包含特定的值。例如,结束用户的注册过程前,可能需要检查他提供的用户名是否已包含在用户名列表中。在地图程序中,可能需要检查用户提交的位置是否包含在已知位置列表中。
要判断特定的值是否已包含在列表中,可使用关键字 in 。来看你可能为比萨店编写的一些代码;这些代码首先创建一个列表,其中包含用户点的比萨配料,然后检查特定的配料是否包含在该列表中。
这种技术很有用,它让你能够在创建一个列表后,轻松地检查其中是否包含特定的值。
5.2.7 检查特定值是否不包含在列表中
还有些时候,确定特定的值未包含在列表中很重要;在这种情况下,可使用关键字 not in 。
5.2.8 布尔表达式
术语 布尔表达式 ,它不过是条件测试的别名。与条件表达式一样,布尔表达式的结果要么为 True ,要么为 False 。
在跟踪程序状态或程序中重要的条件方面,布尔值提供了一种高效的方式。
5.3 if 语句
5.3.1 简单的 if 语句
假设有一个表示某人年龄的变量,而你想知道这个人是否够投票的年龄,可使用如下代码:
5.3.2 if-else 语句
if-else 结构非常适合用于要让 Python 执行两种操作之一的情形。
5.3.3 if-elif-else 结构
如果只使用一条 if 语句,如何确定门票价格呢?
1 age=25 2 if age<4: 3 print("Your admission cost is $0.") 4 elif age<18: 5 print("Your admission cost is $5.") 6 else: 7 print("Your admission cost is $10.")
为让代码更简洁,可不在 if-elif-else 代码块中打印门票价格,而只在其中设置门票价格,并在它后面添加一条简单的 print 语句:
1 age=25 2 if age<4: 3 price=0 4 elif age<18: 5 price=5 6 else: 7 price=10 8 print("Your adminission cost is $"+str(price)+".")
这些代码的输出与前一个示例相同,但 if-elif-else 结构的作用更小,它只确定门票价格,而不是在确定门票价格的同时打印一条消息。除效率更高外,这些修订后的代码
还更容易修改:要调整输出消息的内容,只需修改一条而不是三条 print 语句。
5.3.4 使用多个 elif 代码块
假设对于 65 岁(含)以上的老人,可以半价(即 5 美元)购买门票:
1 age=99 2 if age<4: 3 price=0 4 elif age<18: 5 price=5 6 elif age<65: 7 price=10 8 else: 9 price=5 10 print("Your adminission cost is $"+str(price)+".")
5.3.5 省略 else 代码块
Python 并不要求 if-elif 结构后面必须有 else 代码块。在有些情况下, else 代码块很有用;而在其他一些情况下,使用一条 elif 语句来处理特定的情形更清晰:
1 age=99 2 if age<4: 3 price=0 4 elif age<18: 5 price=5 6 elif age<65: 7 price=10 8 elif age>=65: 9 price=5 10 print("Your adminission cost is $"+str(price)+".")
else 是一条包罗万象的语句,只要不满足任何 if 或 elif 中的条件测试,其中的代码就会执行,这可能会引入无效甚至恶意的数据。如果知道最终要测试的条件,应考虑使用一个 elif 代码块来代替 else 代码块。这样,你就可以肯定,仅当满足相应的条件时,你的代码才会执行。(这些编程设计思想很有用)
5.3.6 测试多个条件
if-elif-else 结构功能强大,但仅适合用于只有一个条件满足的情况:遇到通过了的测试后, Python 就跳过余下的测试。这种行为很好,效率很高,让你能够测试一个特定的
条件。
然而,有时候必须检查你关心的所有条件。在这种情况下,应使用一系列不包含 elif 和 else 代码块的简单 if 语句。在可能有多个条件为 True ,且你需要在每个条件为 True
时都采取相应措施时,适合使用这种方法。
下面再来看前面的比萨店示例。如果顾客点了两种配料,就需要确保在其比萨中包含这些配料:
1 requested_toppings=['mushrooms','extra cheese'] 2 if 'mushrooms' inrequested_toppings: 3 print("Adding mushrooms.") 4 if 'pepperoni' inrequested_toppings: 5 print("Adding pepperoni.") 6 if 'extra cheese' inrequested_toppings: 7 print("Adding extra cheese.") 8 9 print("Finished making your pizza!")
如果像下面这样转而使用 if-elif-else 结构,代码将不能正确地运行,因为有一个测试通过后,就会跳过余下的测试:
1 requested_toppings = ['mushrooms', 'extra cheese'] 2 if 'mushrooms' inrequested_toppings: 3 print("Adding mushrooms.") 4 elif 'pepperoni' inrequested_toppings: 5 print("Adding pepperoni.") 6 elif 'extra cheese' inrequested_toppings: 7 print("Adding extra cheese.") 8 print("Finished making your pizza!")
第一个测试检查列表中是否包含 'mushrooms' ,它通过了,因此将在比萨中添加蘑菇。然而, Python 将跳过 if-elif-else 结构中余下的测试,不再检查列表中是否包
含 'extra cheese' 和 'pepperoni' 。其结果是,将添加顾客点的第一种配料,但不会添加其他的配料:
总之,如果你只想执行一个代码块,就使用 if-elif-else 结构;如果要运行多个代码块,就使用一系列独立的 if 语句。
5.4 使用 if 语句处理列表
5.4.1 检查特殊元素
继续使用前面的比萨店示例。这家比萨店在制作比萨时,每添加一种配料都打印一条消息。通过创建一个列表,在其中包含顾客点的配料,并使用一个循环来指出添加到比萨中
的配料,可以以极高的效率编写这样的代码:
1 requested_toppings = ['mushrooms', 'green peppers', 'extra cheese'] 2 for requested_topping inrequested_toppings: 3 print("Adding " + requested_topping + ".") 4 print("Finished making your pizza!")
输出很简单,因为上述代码不过是一个简单的 for 循环:
然而,如果比萨店的青椒用完了,该如何处理呢?为妥善地处理这种情况,可在 for 循环中包含一条 if 语句:
1 requested_toppings = ['mushrooms', 'green peppers', 'extra cheese'] 2 for requested_topping inrequested_toppings: 3 if requested_topping == 'green peppers': 4 print("Sorry, we are out of green peppers right now.") 5 else: 6 print("Adding " + requested_topping + ".") 7 print("Finished making your pizza!")
5.4.2 确定列表不是空的
在运行 for 循环前确定列表是否为空很重要。
下面在制作比萨前检查顾客点的配料列表是否为空。如果列表是空的,就向顾客确认他是否要点普通比萨;如果列表不为空,就像前面的示例那样制作比萨:
1 requested_toppings =[] 2 ifrequested_toppings: 3 for requested_topping inrequested_toppings: 4 print("Adding " + requested_topping + ".") 5 print("Finished making your pizza!") 6 else: 7 print("Are you sure you want a plain pizza?")
5.4.3 使用多个列表
顾客的要求往往五花八门,在比萨配料方面尤其如此。如果顾客要在比萨中添加炸薯条,该怎么办呢?可使用列表和 if 语句来确定能否满足顾客的要求。
来看看在制作比萨前如何拒绝怪异的配料要求。下面的示例定义了两个列表,其中第一个列表包含比萨店供应的配料,而第二个列表包含顾客点的配料。这次对
于 requested_toppings 中的每个元素,都检查它是否是比萨店供应的配料,再决定是否在比萨中添加它:
1 available_toppings = ['mushrooms', 'olives', 'green peppers', 2 'pepperoni', 'pineapple', 'extra cheese'] 3 requested_toppings = ['mushrooms', 'french fries', 'extra cheese'] 4 for requested_topping inrequested_toppings: 5 if requested_topping inavailable_toppings: 6 print("Adding " + requested_topping + ".") 7 else: 8 print("Sorry, we don't have " + requested_topping + ".") 9 print("Finished making your pizza!")
5.5 设置 if 语句的格式
本章的每个示例都展示了良好的格式设置习惯。在条件测试的格式设置方面, PEP 8 提供的唯一建议是,在诸如 == 、 >= 和 <= 等比较运算符两边各添加一个空格,例如, if
age < 4: 要比 if age<4: 好。
这样的空格不会影响 Python 对代码的解读,而只是让代码阅读起来更容易。
第 6 章 字典
理解字典后,你就能够更准确地为各种真实物体建模。你可以创建一个表示人的字典,然后想在其中存储多少信息就存储多少信息:姓名、年龄、地址、职业以及要描述的任何方面。你还能够存储任意两种相关的信息,如一系列单词及其含义,一系列人名及其喜欢的数字,以及一系列山脉及其海拔等。
6.1 一个简单的字典
来看一个游戏,其中包含一些外星人,这些外星人的颜色和点数各不相同。下面是一个简单的字典,存储了有关特定外星人的信息:
1 aliens_0={'color':'green','points':5} 2 print(aliens_0['color']) 3 print(aliens_0['points'])
字典 alien_0 存储了外星人的颜色和点数。使用两条 print 语句来访问并打印这些信息,如下所示:
green
5
与大多数编程概念一样,要熟练使用字典,也需要一段时间的练习。使用字典一段时间后,你就会明白为何它们能够高效地模拟现实世界中的情形。
6.2 使用字典
在 Python 中, 字典 是一系列 键 — 值对 。每个键 都与一个值相关联,你可以使用键来访问与之相关联的值。与键相关联的值可以是数字、字符串、列表乃至字典。事实上,可将
任何 Python 对象用作字典中的值。
在 Python 中,字典用放在花括号 {} 中的一系列键 — 值对表示。
键 — 值 对是两个相关联的值。指定键时, Python 将返回与之相关联的值。键和值之间用冒号分隔,而键 — 值对之间用逗号分隔。在字典中,你想存储多少个键 — 值对都可以。
最简单的字典只有一个键 — 值对,如下述修改后的字典 alien_0 所示:
1 alien_0 = {'color': 'green'}
这个字典只存储了一项有关 alien_0 的信息,具体地说是这个外星人的颜色。在这个字典中,字符串 'color' 是一个键,与之相关联的值为 'green' 。
6.2.1 访问字典中的值
要获取与键相关联的值,可依次指定字典名和放在方括号内的键,如下所示:
1 alien_0 = {'color': 'green'} 2 print(alien_0['color'])
这将返回字典 alien_0 中与键 'color' 相关联的值:
green
字典中可包含任意数量的键 — 值对。
如果玩家射杀了这个外星人,你就可以使用下面的代码来确定玩家应获得多少个点:
1 aliens_0={'color':'green','points':5} 2 new_points=aliens_0['points'] 3 print("You just earned "+str(new_points)+"points.")
上述代码首先定义了一个字典,然后从这个字典中获取与键 'points' 相关联的值(见❶),并将这个值存储在变量 new_points 中。接下来,将这个整数转换为字符串,并打印一条消息,指出玩家获得了多少个点(见❷):
You just earned 5 points.
6.2.2 添加键 — 值对
字典是一种动态结构,可随时在其中添加键 — 值对。要添加键 — 值对,可依次指定字典名、用方括号括起的键和相关联的值。
下面在字典 alien_0 中添加两项信息:外星人的 x 坐标和 y 坐标,让我们能够在屏幕的特定位置显示该外星人。我们将这个外星人放在屏幕左边缘,且离屏幕上边缘 25 像素的地
方。由于屏幕坐标系的原点通常为左上角,因此要将该外星人放在屏幕左边缘,可将 x 坐标设置为 0 ;要将该外星人放在离屏幕顶部 25 像素的地方,可将 y 坐标设置为 25 ,如下所
示:
1 aliens_0={'color':'green','points':5} 2 print(aliens_0) 3 4 aliens_0['x_position']=0 5 aliens_0['y_position']=25 6 print(aliens_0)
我们首先定义了前面一直在使用的字典,然后打印这个字典,以显示其信息快照。在❶处,我们在这个字典中新增了一个键 — 值对,其中的键为 'x_position' ,而值为 0 。在
❷处,我们重复这样的操作,但使用的键为 'y_position' 。打印修改后的字典时,将看到这两个新增的键 — 值对:
{'points': 5, 'color': 'green'} {'points': 5, 'x_position': 0, 'y_position': 25, 'color': 'green'}
注意,键 — 值对的排列顺序与添加顺序不同。Python 不关心键 — 值对的添加顺序,而只关心键和值之间的关联关系。
6.2.3 先创建一个空字典
有时候,在空字典中添加键 — 值对是为了方便,而有时候必须这样做。为此,可先使用一对空的花括号定义一个字典,再分行添加各个键 — 值对。
使用字典来存储用户提供的数据或在编写能自动生成大量键 — 值对的代码时,通常都需要先定义一个空字典。
6.2.4 修改字典中的值
要修改字典中的值,可依次指定字典名、用方括号括起的键以及与该键相关联的新值。例如,假设随着游戏的进行,需要将一个外星人从绿色改为黄色:
aliens_0={'color':'green'} print("The alien is "+aliens_0['color']+".") aliens_0['color']='yellow' print("The alien is now "+aliens_0['color']+".")
输出:
The alien isgreen. The alien is now yellow.
来看一个更有趣的例子:对一个能够以不同速度移动的外星人的位置进行跟踪。为此,我们将存储该外星人的当前速度,并据此确定该外星人将向右移动多远:
alien_0 = {'x_position': 0, 'y_position': 25, 'speed': 'medium'} print("Original x-position: " + str(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("New x-position: " + str(alien_0['x_position']))
由于这是一个速度中等的外星人,因此其位置将向右移动两个单位:
Original x-position: 0
New x-position: 2
这种技术很棒:通过修改外星人字典中的值,可改变外星人的行为。例如,要将这个速度中等的外星人变成速度很快的外星人,可添加如下代码行:
alien_0['speed'] = 'fast'
这样,再次运行这些代码时,其中的 if-elif-else 结构将把一个更大的值赋给变量 x_increment 。
6.2.5 删除键 — 值对
对于字典中不再需要的信息,可使用del 语句将相应的键 — 值对彻底删除。使用 del 语句时,必须指定字典名和要删除的键。
例如,下面的代码从字典 alien_0 中删除键 'points' 及其值:
alien_0 = {'color': 'green', 'points': 5} print(alien_0) del alien_0['points'] print(alien_0)
❶处的代码行让 Python 将键 'points' 从字典 alien_0 中删除,同时删除与这个键相关联的值。输出表明,键 'points' 及其值 5 已从字典中删除,但其他键 — 值对未受影响:
{'points': 5, 'color': 'green'} {'color': 'green'}
注意:删除的键 — 值对永远消失了。
6.2.6 由类似对象组成的字典
在前面的示例中,字典存储的是一个对象(游戏中的一个外星人)的多种信息,但你也可以使用字典来存储众多对象的同一种信息。例如,假设你要调查很多人,询问他们最喜欢的编程语言,可使用一个字典来存储这种简单调查的结果,如下所示:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', }
正如你看到的,我们将一个较大的字典放在了多行中。其中每个键都是一个被调查者的名字,而每个值都是被调查者喜欢的语言。确定需要使用多行来定义字典时,在输入左花
括号后按回车键,再在下一行缩进四个空格,指定第一个键 — 值对,并在它后面加上一个逗号。此后你再次按回车键时,文本编辑器将自动缩进后续键 — 值对,且缩进量与第一
个键 — 值对相同。
定义好字典后,在最后一个键 — 值对的下一行添加一个右花括号,并缩进四个空格,使其与字典中的键对齐。另外一种不错的做法是在最后一个键 — 值对后面也加上逗号,为以
后在下一行添加键 — 值对做好准备。
(这个编程细节设计的说明很用心了)
注意 对于较长的列表和字典,大多数编辑器都有以类似方式设置其格式的功能。对于较长的字典,还有其他一些可行的格式设置方式,因此在你的编辑器或其他源代码中,你可能会看到稍微不同的格式设置方式。
给定被调查者的名字,可使用这个字典轻松地获悉他喜欢的语言:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } print("Sarah's favorite language is " + favorite_languages['sarah'].title()
+".")
这个示例还演示了如何将较长的 print 语句分成多行。单词 print 比大多数字典名都短,因此让输出的第一部分紧跟在左括号后面是合理的。请选择在合适的地方拆
分要打印的内容,并在第一行末尾加上一个拼接运算符( + )。按回车键进入 print 语句的后续各行,并使用 Tab 键将它们对齐并缩进一级。指定要打印的所有内容
后,在 print 语句的最后一行末尾加上右括号。
6.3 遍历字典
一个 Python 字典可能只包含几个键 — 值对,也可能包含数百万个键 — 值对。鉴于字典可能包含大量的数据, Python 支持对字典遍历。字典可用于以各种方式存储信息,因此有多种
遍历字典的方式:可遍历字典的所有键 — 值对、键或值。
6.3.1 遍历所有的键 — 值对
探索各种遍历方法前,先来看一个新字典,它用于存储有关网站用户的信息。下面的字典存储一名用户的用户名、名和姓:
user_0 ={ 'username': 'efermi', 'first': 'enrico', 'last': 'fermi', }
利用本章前面介绍过的知识,可访问 user_0 的任何一项信息,但如果要获悉该用户字典中的所有信息,该怎么办呢?可以使用一个 for 循环来遍历这个字典:
user_0 ={ 'username': 'efermi', 'first': 'enrico', 'last': 'fermi', } for key, value inuser_0.items(): print("Key: " +key) print("Value: " + value)
for 语句的第二部分包含字典名和方法 items() ,它返回一个键 — 值对列表。接下来, for 循环依次将每个键 — 值对存储到指定的两个变量中。在前面的示例中,我
们使用这两个变量来打印每个键及其相关联的值。第一条 print 语句中的 " " 确保在输出每个键 — 值对前都插入一个空行:
Key: last
Value: fermi
Key: first
Value: enrico
Key: username
Value: efermi
注意,即便遍历字典时,键 — 值对的返回顺序也与存储顺序不同。 Python 不关心键 — 值对的存储顺序,而只跟踪键和值之间的关联关系。
在 6.2.6 节的示例 favorite_languages.py 中,字典存储的是不同人的同一种信息;对于类似这样的字典,遍历所有的键 — 值对很合适。如果遍历字典 favorite_languages ,将得到
其中每个人的姓名和喜欢的编程语言。由于其中的键都是人名,而值都是语言,因此我们在循环中使用变量 name 和 language ,而不是 key 和 value ,这让人更容易明白循环
的作用:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for name, language infavorite_languages.items(): print(name.title() + "'s favorite language is " + language.title() + ".")
仅使用几行代码,我们就将全部调查结果显示出来了:
Jen's favorite language is Python. Sarah's favorite language is C. Phil's favorite language is Python. Edward's favorite language is Ruby.
即便字典存储的是上千乃至上百万人的调查结果,这种循环也管用。
6.3.2 遍历字典中的所有键
在不需要使用字典中的值时,方法 keys() 很有用。下面来遍历字典 favorite_languages ,并将每个被调查者的名字都打印出来:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for name infavorite_languages.keys(): print(name.title())
Python 提取字典 favorite_languages 中的所有键,并依次将它们存储到变量 name 中。输出列出了每个被调查者的名字:
Jen
Sarah
Phil
Edward
遍历字典时,会默认遍历所有的键,因此,如果将上述代码中的 for name in favorite_languages.keys(): 替换为for name in favorite_languages:,输出将不变。
如果显式地使用方法 keys() 可让代码更容易理解,你可以选择这样做,但如果你愿意,也可省略它。
在这种循环中,可使用当前键来访问与之相关联的值。下面来打印两条消息,指出两位朋友喜欢的语言。我们像前面一样遍历字典中的名字,但在名字为指定朋友的名字时,打印一条消息,指出其喜欢的语言:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } friends=['phil','sarah'] for name infavorite_languages: print(name.title()) if name infriends: print("Hi " + name.title() + ", I see your favorite language is " + favorite_languages[name].title() + "!")
我们创建了一个列表,其中包含我们要通过打印消息,指出其喜欢的语言的朋友。在循环中,我们打印每个人的名字,并检查当前的名字是否在列表 friends 中。如果在列表中,就打印一句特殊的问候语,其中包含这位朋友喜欢的语言。为访问喜欢的语言,我们使用了字典名,并将变量 name 的当前值作为键。每个人的名字都会被打印,但只对朋友打印特殊消息:
Edward Phil Hi Phil, I see your favorite language isPython! Sarah Hi Sarah, I see your favorite language isC! Jen
你还可以使用 keys() 确定某个人是否接受了调查。下面的代码确定 Erin 是否接受了调查:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } if 'erin' not infavorite_languages.keys(): print("Erin, please take our poll!")
方法 keys() 并非只能用于遍历;实际上,它返回一个列表,其中包含字典中的所有键,因此代码行只是核实 'erin' 是否包含在这个列表中。由于她并不包含在这个列表中,因此打印一条消息,邀请她参加调查:
Erin, please take our poll!
6.3.3 按顺序遍历字典中的所有键
字典总是明确地记录键和值之间的关联关系,但获取字典的元素时,获取顺序是不可预测的。这不是问题,因为通常你想要的只是获取与键相关联的正确的值。
要以特定的顺序返回元素,一种办法是在 for 循环中对返回的键进行排序。为此,可使用函数 sorted() 来获得按特定顺序排列的键列表的副本:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } for name insorted(favorite_languages.keys()): print(name.title() + ", thank you for taking the poll.")
这条 for 语句类似于其他 for 语句,但对方法 dictionary.keys() 的结果调用了函数 sorted() 。这让 Python 列出字典中的所有键,并在遍历前对这个列表进行排序(按照首字母大小写)。输出
表明,按顺序显示了所有被调查者的名字:
Edward, thank you fortaking the poll. Jen, thank you fortaking the poll. Phil, thank you fortaking the poll. Sarah, thank you for taking the poll.
6.3.4 遍历字典中的所有值
如果你感兴趣的主要是字典包含的值,可使用方法 values() ,它返回一个值列表,而不包含任何键。例如,如果我们想获得一个这样的列表,即其中只包含被调查者选择的各
种语言,而不包含被调查者的名字,可以这样做:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } print("The following languages have been mentioned:") for language infavorite_languages.values(): print(language.title())
这条 for 语句提取字典中的每个值,并将它们依次存储到变量 language 中。通过打印这些值,就获得了一个列表,其中包含被调查者选择的各种语言:
The following languages have been mentioned:
Python
C
Python
Ruby
这种做法提取字典中所有的值,而没有考虑是否重复。涉及的值很少时,这也许不是问题,但如果被调查者很多,最终的列表可能包含大量的重复项。为剔除重复项,可使用集合( set )。集合 类似于列表,但每个元素都必须是独一无二的:
favorite_languages ={ 'jen': 'python', 'sarah': 'c', 'edward': 'ruby', 'phil': 'python', } print("The following languages have been mentioned:") for language inset(favorite_languages.values()): print(language.title())
通过对包含重复元素的列表调用 set() ,可让 Python 找出列表中独一无二的元素,并使用这些元素来创建一个集合。在❶处,我们使用了 set() 来提
取 favorite_languages.values() 中不同的语言。
结果是一个不重复的列表,其中列出了被调查者提及的所有语言:
The following languages have been mentioned:
Python
C
Ruby
随着你更深入地学习 Python ,经常会发现它内置的功能可帮助你以希望的方式处理数据。