第2 章 Python简介

 
尽管每种编程语言都具有各自的特点(实际上这些特点没有语言设计者宣称的那么多),但
在某些方面,它们还是有共同之处的。
 低级编程与高级编程:二者之间的区别是,编写程序时,我们是使用机器层次的指令和
数据对象(例如,将64位数据从一个位置移动到另一个位置),还是使用语言设计者提供
的更为抽象的操作(例如,在屏幕上弹出一个菜单)。
 通用性与专注于某一应用领域:指编程语言中的基本操作是广泛适用的还是只针对某个
领域。例如,SQL设计的目的是使你更容易地从关系数据库提取信息,但你不能指望它去
建立一个操作系统。
 解释运行与编译运行:指程序员编写的指令序列,即源代码是直接执行(通过解释器)
的,还是要先转换(通过编译器)成机器层次的基础操作序列。(在早期的计算机中,
人们必须使用与机器编码非常相似的语言来编写源代码,这种代码可以直接被计算机硬
件解释执行。)这两种方法各有优势。使用解释型语言编写的程序更易调试,因为解释
器可以给出与源代码相关的错误信息。而编译型语言编写的程序速度更快,占用的空间
也更少。
在本书中,我们使用的语言是Python,但不仅限于Python。虽然本书可以帮助读者学习
Python,但更重要的是,细心的读者可以从中学会如何通过编写程序解决问题。这种技能可以转
化到任何一种编程语言中。
Python是一门通用性编程语言,几乎可以快速创建任何类型的程序,而不需要直接访问计
算机硬件。然而,如果想创建高可靠性的程序,Python并不是最好的选择(因为它的静态语义
检查比较弱)。同样,它也不适于需要多人或长时间编写与维护的程序(原因还是糟糕的静态
语义检查)。
但是,相对于多数其他语言,Python确实有一些过人之处。它相当简单,易于学习。因为Python
是解释型语言,所以能够提供实时反馈,这对编程新手特别有用。Python还可以调用大量免费的
程序库,极大地扩展了自己的功能。本书也会用到一些库。
下面开始学习Python中的一些基本元素。这些概念几乎对所有语言都是通用的,只是在实现
细节上有所差别。
需要提醒各位,本书并不会全面介绍Python。我们只是将Python作为一个工具,目的是阐明并思考和解决计算问题相关的概念。当这个隐含目标有需要的时候,我们会零零散散地介绍一些
语言知识,至于与这个目标无关的Python特性则根本不会提及。我们认为这样做没有什么问题,
因为现在有无数优秀的在线资源,几乎涵盖了这门语言的各个方面。讲授本书基于的课程时,我
们建议学生使用这些免费的在线资源作为Python的参考资料。
Python是一门鲜活的语言。自从吉多·范·罗苏姆1990年发明Python以来,它已经发生了很
多变化。最初的10年中,Python默默无闻,备受冷落。直到2000年Python推出2.0版本,情况才发
生转变。除了语言本身实现了很多重要的改进,其演化路径也发生了标志性的转变。很多人开始
开发可以与Python无缝对接的程序库,并提供持续性的支持。Python生态系统下的开发成为一种
基于社区的活动。Python 3.0在2008年末发布。这个版本的Python修正了Python 2的多个发布版本
(通常称为Python 2.x)在设计上的不一致。但是,它不是向后兼容的,这意味着大多数使用Python
以前版本编写的程序不能在Python 3中正常运行。
过去的几年中,多数重要领域的Python程序库都转向了Python 3,并使用Python 3.5进行了充
分的测试,这就是本书所使用的Python版本。

2.1 Python 基本元素
Python程序有时称为脚本,是一系列定义和命令。Python解释器,有时称为shell,用来求值
这些定义并执行命令。一般情况下,每次开始执行一个程序都会创建一个新的shell,通常也会打
开一个窗口。
我们建议你现在打开一个Python shell,并用它运行本章后续部分的示例代码。在本书后面的
内容中,你也可以这样做。
命令通常称为语句,用来指示解释器做一些事情。例如,语句print('Yankees rule!')指
示解释器调用print函数①,并在shell窗口输出字符串Yankees rule!。
以下命令序列:

print 'Yankees rule!'
print 'But not in Boston!'
print 'Yankees rule,', 'but not in Boston!'
会使解释器生成如下输出:
Yankees rule!
But not in Boston!
Yankees rule, but not in Boston!
请注意,第三条语句中,有两个值会被传递给print。print函数可以接受任意数量的参数,由
逗号分隔,然后按照原来的顺序输出,由空格隔开。②

2.1.1 对象、表达式和数值类型
对象是Python程序处理的核心元素。每个对象都有类型,定义了程序能够在这个对象上做的
操作。
类型分为标量和非标量。标量对象是不可分的,可以把它们视为语言中的原子①。非标量对
象,比如字符串,具有内部结构。
在程序文本中,很多类型的对象可以用字面量表示。例如,文本2是个表示数值的字面量,
文本'abc'则是一个表示字符串的字面量。
Python有以下4类标量对象。
 int:表示整数。int类型的字面量在形式上与通常的整数一样(如-3、5或10 002)。
 float:表示实数。float类型的字面量总是包括一个小数点(如3.0、3.17或-28.72)。
(还可以用科学计数法表示float类型的字面量,如字面量1.6E3表示1.6*103,也就是
1600.0。)你可能很好奇,这个类型为什么不称为real。在计算机中,float类型的值是
以浮点数的形式保存的。所有现代编程语言都使用这种表示方法,它有很多优点。但是,
在某些情况下,使用浮点数计算与使用实数计算会有一些微小的差别。我们会在3.4节详
加讨论。
 bool:表示布尔值True和False。
 None:这个类型只有一个值。4.1节将详细讨论。
对象和操作符可以组成表达式,每个表达式都相当于某种类型的对象,我们称其为表达式的
值。例如,表达式3 + 2表示int类型的对象5,表达式3.0 + 2.0表示float类型的对象5.0。
==操作符用来检验两个表达式的值是否相等,!=操作符用来检验两个表达式的值是否不等。
单个=的意义完全不同,我们会在2.1.2节介绍。预先警告一下,如果你在应该使用==的地方使用
了=,就会出现一个错误,请随时注意。
符号>>>是shell提示符,表示解释器正等待用户向shell输入某些Python代码。解释器对在提
示符处输入的代码进行求值之后,会在提示符所在行的下一行显示代码结果,用户与解释器的交
互过程如下所示:
>>> 3 + 2
5
>>> 3.0 + 2.0
5.0
>>> 3 != 2
True
可以使用Python内置函数type给出对象类型:
>>> type(3)
<type 'int'>
>>> type(3.0)
<type 'float'>

int类型和float类型支持的操作符如图2-1所示。

i + j:i和j的和。如果i和j都是int类型,结果也是int类型;如果其中任意一个是float
类型,那么结果就是float类型。
i - j:表示i减j。如果i和j都是int类型,结果也是int类型;如果其中任意一个是float
类型,那么结果就是float类型。
i * j:i和j的积。如果i和j都是int类型,结果也是int类型;如果其中任意一个是float
类型,那么结果就是float类型。
i // j:表示整数除法。例如,6 // 2的值是3,int类型。6 // 4的值是1,int类型。
值为1的原因是整数除法只返回商,不返回余数。如果j == 0,会发生一个错误。
i / j:表示i除以j。在Python 3中,/操作符执行的是浮点数除法。例如,6 / 4的值是
1.5。如果j == 0,会发生一个错误。(在Python 2中,当i和j都是int类型时,/操作符和
//操作符一样,返回int类型的结果。如果i或j中任意一个是float类型,那么/操作符和
Python 3中的/操作符一样,返回float类型的结果。)
i % j:表示int i除以int j的余数。通常读作i mod j,是i modulo j的缩写。
i ** j:表示i的j次方。如果i和j都是int类型,结果也是int类型。如果其中任意一个
是float类型,那么结果就是float类型。
比较运算符包括:==(等于)、!=(不等于)、>(大于)、>=(大于等于)、<(小于)
和<=(小于等于)。
图2-1 int类型和float类型支持的操作符

算术操作符一般具有优先级。例如,*的优先级比+要高,所以表达式x + y * 2要先计算y
乘以2,再将结果与x相加。通过使用圆括号将表达式的一部分括起来,可以改变计算顺序,如
(x + y) * 2先计算x加y,再将结果与2相乘。
bool类型上的基本操作符为and、or和not。
 a and b:当a和b都为True时,值为True,否则为False。
 a or b:当a和b至少有一个为True时,值为True,否则为False。
 not a:如果a为False,值为True;如果a为True,值为False。

2.1.2 变量与赋值
变量将名称与对象关联起来。看下面的代码:
pi = 3
radius = 11
area = pi * (radius**2)
radius = 14
这段代码先将名称pi和radius绑定到两个int类型的对象。①然后将名称area绑定到第三个int类
型的对象,如图2-2中左图所示。

图2-2 将变量绑定到对象

如果程序接着执行radius = 14,名称radius就被重新绑定到一个新的int类型的对象,如图
2-2中右图所示。请注意,这次赋值对area绑定的值没有影响,它仍然绑定到由表达式3 * (11 ** 2)
表示的对象。
在Python中,变量仅是名称,没有其他意义。请牢记这一点,这非常重要。赋值语句将=左
边的名称与=右边的表达式所表示的对象关联起来,也请牢记这一点。一个对象可以有一个或多
个名称与之关联,也可以不关联任何名称。
也许我们不应该说“变量仅是名称”。不管朱丽叶怎么说①,名称还是很重要的。编程语言可
以让我们用一种机器可执行的方式描述计算过程,但这并不意味着只有计算机会阅读你的程序。
你很快就会发现,编写运行顺畅的程序可不是一件容易的事。经验丰富的程序员会肯定地告
诉你,为了弄清楚程序的工作方式,他们会花费大量时间阅读程序。因此,将程序写得清晰易懂
极其重要,恰当地选择变量名称在增强程序可读性方面扮演了重要角色。
看看下面两段代码:
a = 3.14159 pi = 3.14159
b = 11.2 diameter = 11.2
c = a*(b**2) area = pi*(diameter**2)
就Python本身来讲,这两段代码没有区别,运行时,它们会做同样的事情。但对于人类读者,它
们则迥然不同。当你阅读左侧的代码片段时,没有任何先验理由可以怀疑哪里出了错误。但对于
右侧代码,我们可以一眼就看出其中有错。或者将本应该命名为radius的变量错误命名为
diameter,或者应该在计算面积的时候将diameter除以2.0。
在Python中,变量名可以包含大写字母、小写字母、数字(但不能以数字开头)和特殊字
符_。Python变量名是大小写敏感的,如Julie和julie就是不同的变量名。最后,Python中还
有少量的保留字(有时称为关键字),它们有专门的意义,不能用作变量名。不同版本的Python中,保留字有些微小的区别。Python 3中的保留字包括and、as、assert、break、class、
continue、def、del、elif、else、except、False、finally、for、from、global、if、
import、in、is、lambda、nonlocal、None、not、or、pass、raise、return、True、try、
while、with和 yield。
另外一种提高可读性的好方法是添加注释。Python不解释符号#后面的文本。例如,我们可
以这样在代码中写注释:
side = 1 #单位正方形的边长
radius = 1 #单位圆形的半径
#从圆C的面积中减去正方形S的面积
areaC = pi*radius**2
areaS = side*side
difference = areaS - areaC
Python支持多重赋值。以下语句:
x, y = 2, 3
将x绑定到2,将y绑定到3。赋值语句右侧的每个表达式先进行求值,然后分别与左侧的变量名绑
定。这种操作非常方便,因为可以使用多重赋值交换对两个变量的绑定。
例如,以下代码:
x, y = 2, 3
x, y = y, x
print ('x =', x)
print ('y =', y)
会输出:
x = 3
y = 2

2.1.3 Python IDE
直接在shell中编写程序非常不方便。多数程序员更愿意在集成开发环境下使用文本编辑器编
写程序。
Python标准安装包中提供了一种IDE,这就是IDLE①。随着Python逐渐流行,其他IDE也开始
涌现。这些新的IDE经常会集成一些常用的Python程序库,并提供IDLE中没有的便捷。Anaconda
和Canopy就是其中的佼佼者,本书中的代码就是使用Anaconda编写和测试的。
IDE是一种应用程序,和计算机中的其他应用程序一样,可以像启动其他应用一样启动IDE,
比如双击图标。
Python IDE提供以下功能:
 具有语法高亮、自动补全和智能缩进功能的文本编辑器;

 具有语法高亮功能的shell程序;
 集成调试器,可以暂时忽略。
IDE启动时,会打开一个shell窗口,你可以在其中输入Python命令,同时还会有一个文件菜
单和一个编辑菜单(还可能有其他菜单,提供更多便捷操作,如输出程序)。
文件菜单中的常用命令包括:
 创建一个新编辑窗口,你可以在其中输入Python程序;
 打开一个包含Python程序的文件;
 将当前编辑窗口中的内容保存到一个文件(扩展名为.py)。
编辑菜单包含标准的文本编辑命令(如复制、粘贴与查找),以及一些为方便编辑Python代
码专门设计的命令(如区段缩进与区段注释)。
想了解常用IDE的更多知识,可以访问:
http://docs.python.org/library/idle.html/
https://store.continuum.io/cshop/anaconda/
https://www.enthought.com/products/canopy

2.2 程序分支
迄今为止,我们讨论的计算类型都可以称为直线型程序。它们按照语句出现的顺序逐条执行,
并在执行完所有语句后结束。这种用直线型程序实现的计算没有太大价值,实际上,无聊透顶。
分支型程序更有价值。最简单的分支语句是条件语句。如图2-3大矩形部分所示,条件语句
包括3部分。
 一个测试:即一个表达式,取值或者为True,或者为False。
 一个代码块:测试条件取值为True时执行。
 一个可选代码块:测试条件取值为False时执行。
条件语句执行完毕后,程序会接着执行后面的语句。

图2-3 条件语句流程图

在Python中,条件语句具有以下形式:
if Boolean expression:
block of code
else:
block of code
或者:
if Boolean expression:
block of code
描述Python语句形式的时候,我们用斜体描述可能出现在程序该处的代码。例如,Boolean
expression表示一个表达式,它的取值为True或False,可以用在if保留字后面。block of code
表示可以跟在else:后面的Python语句序列。
看看下面的程序,它在变量x为偶数的时候输出Even,否则输出Odd:
if x%2 == 0:
print 'Even'
else:
print 'Odd'
print 'Done with conditional'
当x除以2的余数为0时,表达式x % 2 == 0取值为True,否则为False。请记住,==是用来
做比较运算的,因为=用于赋值。
缩进在Python中是具有语义意义的。例如,如果上面代码中的最后一条语句是缩进的,那么
它就会属于else代码块,而不是与条件语句并列的语句。
Python在对缩进的使用上独树一帜。多数其他编程语言使用某种括号表示代码块,如C语言
使用{ }封装代码块。Python的缩进处理方法的优点是,它确保了程序的外观结构可以准确表达
程序的语义结构。因为缩进在语义上非常重要,所以每行代码的意义都很重要。
当条件语句的True代码块或False代码块中又包含一个条件语句时,我们说这个条件语句是
嵌套的。在下面的代码中,最高层if语句的两个分支中都有嵌套的条件语句。
if x%2 == 0:
if x%3 == 0:
print 'Divisible by 2 and 3'
else:
print 'Divisible by 2 and not by 3'
elif x%3 == 0:
print 'Divisible by 3 and not by 2'
上面代码中的elif表示else if。
在条件语句的检验条件中,使用复合布尔表达式是非常方便的,例如:
if x < y and x < z:
print('x is least')
elif y < z:
print('y is least')
else:
print('z is least')

条件语句可以使我们将程序编写得比直线型程序更有趣,但分支型程序的等级仍然有限。对
于某种等级的程序,衡量其能力的方法可以是看看它能够运行多长时间。假定每行代码都需要以单
位时间运行,那么有n行代码的直线型程序就需要n个单位时间。那么有n行代码的分支型程序呢?
它运行的时间可能会少于n个单位时间,但绝不会超过n个单位时间,因为每行代码至多运行一次。
如果一个程序运行的最长时间是由程序长度决定的,那么可以称为以常数时间运行。这并不
意味着它每次运行都执行相同的步骤,而意味着存在一个常数k,使得这个程序肯定会在k个步骤
之内结束运行。其中隐含的意义是,这种程序的运行时间并不随着程序输入量的增加而增加。
常数时间程序的功能很有限。例如,我们要编写一个程序计算一次选举中的投票总数。如果
有人可以写出一个程序,能在与投票数量无关的时间内完成这个任务,那简直是一个奇迹。实际
上,我们可以证明,这是不可能的。这种对问题固有的困难性的研究属于计算复杂度的范畴。在
本书中,我们还会多次提及这个话题。
幸运的是,我们只需要另一种编程语言基本结构——迭代——即可编写具有任意复杂度的程
序。我们会在2.4节介绍这部分内容。
实际练习:编写一个程序,检查3个变量x、y和z,输出其中最大的奇数。如果其中没有奇数,
就输出一个消息进行说明。
2.3 字符串和输入
str类型的对象用来表示由字符组成的字符串。①str类型的字面量可以用单引号或双引号表
示,如'abc'或"abc"。字面量'123'表示有3个字符的字符串,而不是数值123。
试着在Python解释器中输入以下表达式(请记住>>>是提示符,无需输入):
>>> 'a'
>>> 3*4
>>> 3*'a'
>>> 3+4
>>> 'a'+'a'
这里的操作符+被称为重载,根据应用其上的对象类型的不同,它的意义也不同。例如,应
用于两个数值对象时,它表示相加;应用于两个字符串时,它表示连接。操作符*也是重载。当
它两侧的操作数都是数值对象时,其意义和你想的一样。当应用于一个int类型和一个str类型的
对象时,它就成了重复操作符:表达式n * s。这里n是一个int对象,s是一个str对象,表达式
的值就是一个将s重复n次的str对象。例如,表达式2 * 'John'的值是'JohnJohn'。逻辑是这样
的,就像数学表达式3 * 2等于2 + 2 + 2一样,表达式3 * 'a'就等于'a' + 'a' + 'a'。
试着输入:
>>> a
>>> 'a'*'a'

每行代码都会产生一个错误消息。第一行的错误消息是:
NameError: name 'a' is not defined
因为a不是任何一种类型的字面量,解释器会将它当作一个名称。但因为这个名称没有与任何一
个对象绑定,所以对它的使用会引起一个运行时错误。代码'a' * 'a'产生的错误消息是:
TypeError: can't multiply sequence by non-int of type 'str'
类型检查的存在是件好事。它可以检查出由于粗心(有时确实很不明显)而使程序停止运行
的错误,从而避免程序以无法预知的状态运行,导致更严重的后果。Python中的类型检查不如某
些其他语言严格(如Java),但Python 3中的检查要强于Python 2。例如,Python 3中明确规定了<
在比较两个字符串或两个数值时的意义。但是'4' < 3应如何取值?这就不太明确了。Python 2
的设计者认为这个表达式的值应该是False,因为所有数值类型的值都应该小于所有str类型的
值。Python 3以及多数其他现代语言设计者的观点则是,既然这个表达式没有明显的意义,那么
就应该生成一条错误消息。
字符串是Python中的序列类型之一。所有序列类型都可以执行以下操作。
 可以使用len函数求出字符串的长度。例如,len('abc')的值是3。
 可以使用索引从字符串提取单个字符。在Python中,所有索引都从0开始。例如,在解释
器中输入'abc'[0]会显示字符串'a',输入'abc'[3]会产生一条错误消息IndexError:
string index out of range。因为Python使用0表示字符串中第一个元素,长度为3的字
符串中最后一个元素的索引值是2。可以使用负数表示字符串从末尾开始的索引。例如,
'abc'[-1]的值是'c'。
 可以使用分片操作从字符串提取任意长度的子串。如果s是个字符串,那么表达式
s[start:end]就表示s中从索引start开始至索引end-1结束的子串。例如,'abc'[1:3] =
'bc' 。为什么在索引end-1 处而不是在end 处结束呢? 这样做是为了让
'abc'[0:len('abc')]这样的表达式具有我们希望的值。如果冒号前面的索引值省略,那
么默认值为0;如果冒号后面的索引值省略,那么默认值就是字符串的长度。于是,表达
式'abc'[:]在语义上就等同于更加冗长的'abc'[0:len('abc')]。
2.3.1 输入
Python 3中有一个input函数,可以直接接受用户输入。①它可以使用一个字符串作为参数,
显示在shell中作为提示信息,然后等待用户输入,用户输入以回车键结束。用户输入的行信息被
看作一个字符串,并成为这个函数的返回值。
看下面的代码:
>>> name = input('Enter your name: ')
Enter your name: George Washington

>>> print('Are you really', name, '?')
Are you really George Washington ?
>>> print('Are you really ' + name + '?')
Are you really George Washington?
请注意,在第一个print语句中,输出结果的?前面有一个空格。这是因为,当print语句有多个
参数时,会在每个参数对应的值之间加上一个空格。第二个print语句使用连接生成一个没有多
余空格的字符串,然后作为唯一参数传递给了print语句。
再看看下面的代码:
>>> n = input('Enter an int: ')
Enter an int: 3
>>> print(type(n))
<type 'str'>
请注意,变量n被绑定到字符串'3',而不是整数3。这样表达式n * 4的值就是'3333',而不是
12。好消息是,只要字符串中的值是某种类型的有效字面量,就可以对字符串进行类型转换。
类型转换在Python代码中很常见。我们使用类型名称将一个值转换为这种类型。例如,
int('3') * 4的值是12。当一个float值被转换成int值时,数值是被截断的(不是四舍五入)。
例如,int(3.9)的值是int 3。
2.3.2 杂谈字符编码
多年以来,多数编程语言都使用一种名为ASCII的标准,在计算机内部表示字符。这个标准
包括128个字符,足够表示英语中经常出现的特殊字符。但要表示世界上所有语言中的字符和符
号,那就不够用了。
最近几年,人们逐渐转向Unicode。Unicode标准是一个字符编码系统,支持数字化处理和所
有语言的书面文本显示。这个标准中的字符超过120 000个,覆盖了129种从古至今的语言和符号
集合。通过各种内部字符编码,可以实现Unicode标准。你可以告诉Python使用何种编码方式,
在程序的第一行或第二行插入一条注释即可:
# -*- coding: encoding name -*-
例如:
# -*- coding: utf-8 -*-
可以指示Python使用UTF-8,这是万维网网页上最常使用的字符编码。①如果在程序中找不到这样
的注释,多数Python实现会默认使用UTF-8。
使用UTF-8编码时,如果文本编辑器允许,那么可以直接输入下面的代码:
print('Mluvíš anglicky?')
print('क्या आप अंग्रेज़ी बोलते ह􀉇?')
这会输出:

Mluvíš anglicky?
क्या आप अंग्रेज़ी बोलते ह􀉇?
你可能想知道我是如何输入字符串'क्या आप अंग्रेज़ी बोलते ह􀉇?'的。实际上,我并未手动输入。因
为多数万维网网页是使用UTF-8编码的,所以我可以从一个网页上复制这个字符串,然后直接粘
贴到程序。
2.4 迭代
我们在2.2节末尾得出结论:多数计算任务不能使用分支程序完成。例如,假设要编写一个程
序,先询问用户想输出多少个字母X,然后输出包含该数量X的字符串。可以考虑使用下面的代码:
numXs = int(input('How many times should I print the letter X? '))
toPrint = ''
if numXs == 1:
toPrint = 'X'
elif numXs == 2:
toPrint = 'XX'
elif numXs == 3:
toPrint = 'XXX'
#...
print(toPrint)
大家很快就会发现,需要和正整数一样多的条件从句——无穷个。我们真正需要的是类似于下面
的程序:
numXs = int(input('How many times should I print the letter X? '))
toPrint = ''
concatenate X to toPrint numXs times
print(toPrint)
需要程序多次做同一件事情的时候,可以使用迭代语句。一般的迭代(也称循环)机制如图
2-4矩形框中所示。与条件语句类似,它从一个测试条件开始。如果测试条件取值为True,程序
就执行一次循环体,然后重新检查测试条件。一直重复这个过程,直到测试条件为False,此后
程序控制权就传递给迭代语句后面的代码。

图2-4 迭代流程图

可以使用while语句完成图2-4所示的循环。看下面的示例代码:
# Square an integer, the hard way
x = 3
ans = 0
itersLeft = x
while (itersLeft != 0):
ans = ans + x
itersLeft = itersLeft - 1
print(str(x) + '*' + str(x) + ' = ' + str(ans))
代码首先将变量x和整数3绑定,然后开始通过重复相加求x的平方。每次程序运行到循环开
始的测试条件时,各个变量的值都会发生变化,如图2-5中表格所示。这个表格是我们通过对代
码的手工模拟得到的。也就是说,我们假装自己是Python解释器,使用铅笔和纸执行程序。使用
铅笔和纸看起来颇具古风,但这是弄清楚程序如何运行的一种非常好的方法。①

图2-5 手工模拟一个小程序

当程序第四次检查测试条件时,测试条件的值为False,控制流前进到循环语句后面的print
语句。那么对于何种x值,程序能正常结束呢?我们分3种情况讨论:x == 0、x > 0和x < 0。
假设x == 0,那么itersLeft的初始值也为0,循环体根本不会执行。
假设x > 0,那么itersLeft的初始值会大于0,循环体会至少执行一次。每执行一次循环体,
itersLeft的值就会减1。这说明,如果itersLeft开始于一个大于0的数,那么在有限次的循环
迭代后,itersLeft会等于0。此时循环测试条件的值为False,控制流会前进到while语句后面
的代码。
假设x < 0,那么可怕的事情将会发生。控制流会进入循环,每一次迭代都会使itersLeft
更加远离0。因此,程序会一直不停地执行循环体(或者直到另外一件可怕的事情发生,比如内
存溢出)。那么如何改正程序的这个缺陷呢?可以将itersLeft初始化为x的绝对值。循环将结束,
但会输出一个负值。如果修改循环内部的赋值语句,改为ans = ans + abs(x),那么代码可以
得到正确的结果。
实际练习:将以下代码中的注释替换为while循环语句。
numXs = int(input('How many times should I print the letter X? '))
toPrint = ''

#concatenate X to toPrint numXs times
print(toPrint)
有时候,不用检查循环条件就跳出循环是非常方便的。我们可以使用break语句结束它所在
的循环,将控制流转到紧随循环语句后面的代码中。例如,看下面的代码:
#Find a positive integer that is divisible by both 11 and 12
x = 1
while True:
if x%11 == 0 and x%12 == 0:
break
x = x + 1
print(x, 'is divisible by 11 and 12')
会输出:
132 is divisible by 11 and 12
如果在嵌套的循环语句(位于另一个循环语句内部的循环语句)中执行break语句,那么
break语句会结束内层循环语句。
我们已经介绍了相当多的Python知识,足够编写一些有趣的程序来处理数值和字符串。第3
章先暂停对Python的学习,使用已经掌握的知识解决一些简单的问题。
实际练习:编写一个程序,要求用户输入10个整数,然后输出其中最大的奇数。如果用户没
有输入奇数,则输出一个消息进行说明。

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

___Y1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值