Python培训
400-996-5531
学习目标
知道有序的软件开发过程的步骤。
了解遵循输入、处理、输出(IPO)模式的程序,并能够以简单的方式修改它们。
了解构成有效Python标识符和表达式的规则。
能够理解和编写Python语句,将信息输出到屏幕,为变量赋值,获取通过键盘输入的信息,并执行计数循环。
软件开发过程
运行已经编写的程序很容易。较难的部分实际上是先得到一个程序。计算机是非常实在的,必须告诉它们要做什么,直至最后的细节。编写大型程序是一项艰巨的挑战。如果没有系统的方法,几乎是不可能的。
创建程序的过程通常被分成几个阶段,依据是每个阶段中产生的信息。简而言之,你应该做以下工作。
分析问题 确定要解决的问题是什么。尝试尽可能多地了解它。除非真的知道问题是什么,否则就不能开始解决它。
确定规格说明 准确描述程序将做什么。此时,你不必担心程序“怎么做”,而是要确定它“做什么”。对于简单程序,这包括仔细描述程序的输入和输出是什么以及它们的相互关系。
创建设计 规划程序的总体结构。这是描述程序怎么做的地方。主要任务是设计算法来满足规格说明。
实现设计 将设计翻译成计算机语言并放入计算机。在本书中,我们将算法实现为Python程序。
测试/调试程序 试用你的程序,看看它是否按预期工作。如果有任何错误(通常称为“缺陷”),那么你应该回去修复它们。定位和修复错误的过程称为“调试”程序。在调试阶段,你的目标是找到错误,所以应该尝试你能想到的“打破”程序的一切可能。记住这句老格言:“没有什么能防住人犯傻,因为傻子太聪明了。”
维护程序 继续根据用户的需求开发该程序。大多数程序从来没有真正完成,它们在多年的使用中不断演进。
示例程序:温度转换器
让我们通过一个真实世界的简单例子,来体验软件开发过程的步骤,其中涉及一个虚构的计算机科学学生Susan Computewell。
Susan正在德国学习一年。她对语言没有任何问题,因为她能流利地使用许多语言(包括Python)。她的问题是,很难在早上弄清楚温度从而知道当天该穿什么衣服。Susan每天早上听天气报告,但温度以摄氏度给出,她习惯了华氏度。
幸运的是,Susan有办法解决这个问题。作为计算机科学专业的学生,她去任何地方总是带着她的笔记本计算机。她认为计算机程序可能会帮助她。
Susan开始分析她的问题。在这个例子中,问题很清楚:无线电广播员用摄氏度报气温,但Susan只能理解华氏温度。
接下来,Susan考虑可能帮助她的程序的规格说明。输入应该是什么?她决定程序将允许她输入摄氏温度。输出呢?程序将显示转换后的华氏温度。现在她需要指定输出与输入的确切关系。
苏珊快速估算了一下。她知道0摄氏度(冰点)等于32华氏度,100摄氏度(沸点)等于212华氏度。有了这个信息,她计算出华氏度与摄氏度的比率为(212−32)/(100−0) = (180/100) = 9/5。使用F表示华氏温度,C表示摄氏温度,转换公式的形式为F = (9/5)C + k,其中k为某个常数。代入0和32分别作为C和F,Susan立即得到k = 32。所以最后的关系公式是F = (9/5)C + 32。这作为规格说明似乎足够了。
请注意,这描述了能够解决这个问题的许多可能程序中的一个。如果Susan有人工智能(AI)领域的背景,她可能会考虑写一个程序,用语音识别算法实际收听收音机播音员,获得当前的温度。对于输出,她可以让计算机控制机器人进入她的衣柜,并根据转换后的温度选择适当的服装。这将是一个更有野心的项目,一点也不夸张!
当然,机器人程序也会解决问题分析中识别的问题。规格说明的目的,是准确地决定这个特定的程序要做什么,从而解决一个问题。Susan知道,最好是先弄清楚她希望构建什么,而不是一头钻进去开始编程。
Susan现在准备为她的问题设计一个算法。她马上意识到这是一个简单算法,遵循标准模式“输入、处理、输出”(IPO)。她的程序将提示用户输入一些信息(摄氏温度),处理它,产生华氏温度,然后在计算机屏幕上显示结果,作为输出。
Susan可以用一种计算机语言来写她的算法。然而,正式将它写出来需要相当的精度,这常常会扼杀开发算法的创造性过程。作为替代,她用“伪代码”编写算法。伪代码只是精确的英语,描述了程序做的事。这意味着既可以交流算法,又不必让大脑承担额外的开销,正确写出某种特定编程语言的细节。
下面是Susan的完整算法:
输入摄氏度温度(称为celsius)计算华氏度为(9/5)celsius + 32输出华氏度
下一步是将此设计转换为Python程序。这很直接,因为算法的每一行都变成了相应的Python代码行。
# convert.py# A program to convert Celsius temps to Fahrenheit# by: Susan Computewelldef main(): celsius = eval(input("What is the Celsius temperature? ")) fahrenheit = 9/5 * celsius + 32 print("The temperature is", fahrenheit, "degrees Fahrenheit.")main()
看看你是否能弄清楚这个程序的每一行做了什么。如果一些部分不是很清楚,也不要担心,下一节将详细讨论。
完成程序后,Susan测试它,看看它工作得如何。她使用她知道正确答案的输入。下面是两个测试的输出:
What is the Celsius temperature? 0The temperature is 32.0 degrees Fahrenheit.What is the Celsius temperature? 100The temperature is 212.0 degrees Fahrenheit.
你可以看到,Susan用值0和100来测试她的程序。看起来不错,她对解决方案感到满意。她特别高兴的是,似乎没有必要调试(这很不寻常)。
程序要素
既然已经知道了编程过程,你就“几乎”准备好开始自己编写程序了。在此之前,你需要更完整的基础,了解Python的基本知识。接下来的几节将讨论一些技术细节,这对编写正确程序至关重要。这种材料看起来有点乏味,但你必须掌握这些基础,然后再进入更有趣的领域。
1 名称
你已经看到,名称是编程的重要组成部分。我们为模块命名(例如convert),也为模块中的函数命名(例如main)。变量用于为值命名(例如celsius和fahrenheit)。从技术上讲,所有这些名称都称为“标识符”。Python对标识符的构成有一些规则。每个标识符必须以字母或下划线(“_”字符)开头,后跟字母、数字或下划线的任意序列。这意味着单个标识符不能包含任何空格。
根据上述规则,以下都是Python中的合法名称:
xcelsiusspamspam2SpamAndEggsSpam_and_Eggs
标识符区分大小写,因此对Python来说,spam、Spam、sPam和SPAM是不同的名称。在大多数情况下,程序员可以自由选择符合这些规则的任何名称。好的程序员总是试图选择一些名字,它们能描述被命名的东西。
需要注意一件重要的事情:一些标识符是Python本身的一部分。这些名称称为“保留字”或“关键字”,不能用作普通标识符。Python关键字的完整列表如表1所列。
表1 Python关键字
Python还包括相当多的内置函数,例如我们用过的print函数。虽然在技术上可以将内置的函数名称标识符用于其他目的,但这通常是一个“非常糟糕”的主意。例如,如果你重新定义print的含义,那么就无法再打印信息。你也会让所有阅读程序的Python程序员感到非常困惑,他们预期print指的是内置函数。内置函数的完整列表可在附录A中找到。
2 表达式
程序操作数据。到目前为止,我们已经在示例程序中看到了数字和文本两种不同类型的数据。我们将在后面的节中详细讨论这些不同的数据类型。现在,你只需要记住,所有的数据必须以一些数字格式存储在计算机上,不同类型的数据以不同的方式存储。
产生或计算新数据值的程序代码片段称为“表达式”。最简单的表达式是字面量。字面量用于表示特定值。在chaos.py中,你可以找到数字3.9和1。convert.py程序包含9、5和32。这些都是数字字面量的例子,它们的含义显而易见:32就是代表32(数字32)。
我们的程序还以一些简单的方式处理文本数据。计算机科学家将文本数据称为“字符串”。你可以将字符串视为可打印字符的序列。Python中通过将字符括在引号("")中来表示字符串字面量。如果你回头看看我们的示例程序,可以发现一些字符串字面量,例如"Hello"和"Enter a number between 0 and 1:"。这些字面量产生的字符串包含引号内的字符。请注意,引号本身不是字符串的一部分。它们只是告诉Python创建一个字符串的机制。
将表达式转换为基础数据类型的过程称为“求值”。在Python shell中键入表达式时,shell会计算表达式并打印出结果的文本表示。请考虑以下简短的交互:
>>> 3232>>> "Hello"'Hello'>>> "32"'32'
请注意,当shell显示字符串的值时,它将字符序列放在单引号中。这样让我们知道该值实际上是文本而不是数字(或其他数据类型)。在最后一次交互中,我们看到表达式"32"产生一个字符串,而不是一个数字。在这种情况下,Python实际上是存储字符“3”和“2”,而不是数字32的表示。如果你现在不太明白,不要太担心。我们在后面的节中讨论这些数据类型时,你的理解就会变得更加清晰。
一个简单的标识符也可以是一个表达式。我们使用标识符作为变量来给名字赋值。当标识符作为表达式出现时,它的值会被取出,作为表达式的结果。下面是与Python解释器的交互,展示了变量作为表达式:
>>> x = 5>>> x5>>> print(x)5>>> print(spam)Traceback (most recent call last): File "<stdin>", line 1, in <module>NameError: name 'spam' is not defined
首先,变量x被赋值为5(使用数字字面量5)。在第二行交互中,我们要求Python对表达式x求值。作为响应,Python shell打印出5,这是刚才赋给x的值。当然,如果我们明确要求Python用print语句打印x,也会得到相同的结果。最后一个交互展示了如果尝试使用未赋值的变量,会发生什么。Python找不到值,所以它报告NameError。这说明没有该名称的值。这里的要点是,变量总是必须赋一个值,然后才能在表达式中使用。
较复杂、较有趣的表达式可以通过组合较简单的表达式和操作符来构造。对于数字,Python提供了一组标准的数学运算:加法、减法、乘法、除法和乘方。相应的Python运算符为“+”“-”“*”“/”和“**”。下面是一些来自chaos.py和convert.py的复杂表达式的例子:
3.9 * x * (1 - x)9/5 * celsius + 32
空格在表达式中没有作用。最后一个表达式如果写成9/5*celsius+32,结果完全相同。通常,在表达式中加一些空格让它更容易阅读,是个好方法。
Python的数学运算符遵循的优先级和结合律,与你在数学课上学到的相同,包括使用括号来改变求值的顺序。在自己的程序中构建复杂表达式应该没什么困难。请记住,只有圆括号在数字表达式中是允许的。如果需要,可以嵌套使用它们,创建如下的表达式:
((x1 - x2) / 2*n) + (spam / k**3)
顺便说一句,Python还提供了字符串的运算符。例如,可以“加”字符串。
>>> "Bat" + "man"'Batman'
这被称为“连接”。如你所见,效果是创建一个新的字符串,把两个字符串“粘”在一起。
3 输出语句
既然有了基本的构建块(标识符和表达式),你就可以更完整地描述各种Python语句。 你已经知道信息可以使用Python的内置函数print在屏幕上显示。到目前为止,我们已经看了几个例子,但我还没有详细解释打印功能。像所有的编程语言一样,Python对每个语句的语法(形式)和语义(意义)有一套精确的规则。计算机科学家已经开发了复杂的符号表示法,称为“元语言”,用于描述编程语言。在本书中,我们将依靠一个简单的模板符号表示法来说明各种语句的语法。
因为print是一个内置函数,所以print语句与任何其他函数调用具有相同的一般形式。我们键入函数名print,后面带上括号中列出的参数。下面是用我们的模板符号时print语句看起来的样子:
print(<expr>, <expr>, ..., <expr>)print()
这两个模板展示了两种形式的print语句。第一个表示print语句可以包含函数名print,后面带上带括号的表达式序列,用逗号分隔。模板中的尖括号符号(<>)用于表示由Python代码的其他片段填充的“槽”。括号内的名称表示缺少什么,expr表示一个表达式。省略号(“...”)表示不确定的序列(在这个例子中是表达式)。你实际上不会输入圆点。第二个版本的print语句表明,不打印任何表达式的print也是合法的。
就语义而言,print语句以文本形式显示信息。所有提供的表达式都从左到右求值,结果值以从左到右的方式显示在输出行上。默认情况下,在显示的值之间放置一个空格字符。作为示例,下面print语句的序列:
print(3+4)print(3, 4, 3 + 4)print()print("The answer is", 3 + 4)
产生的输出为:
73 4 7The answer is 7
最后一个语句说明了,字符串字面量表达式如何经常在print语句使用,作为标记输出的方便方法。
注意,连续的print语句通常显示在屏幕的不同行上。空print(无参数)生成空行输出。在背后,真正发生的是,在打印所有提供的表达式之后,print函数自动附加某种结束文本。默认情况下,结束文本是表示行结束的特殊标记字符(表示为“\n”)。我们可以通过包含一个附加参数显式地覆盖这个默认值,从而改变这种行为。这里使用命名参数的特殊语法,或称为“关键字”参数。
包含指定结束文本的关键字参数的print语句的模板如下:
print(<expr>, <expr>, ..., <expr>, end="\n")
命名参数的关键字是end,它使用“=”符号赋值,类似于变量赋值。注意,在模板中我已经显示其默认值,即行末字符。这是一种标准方式,用于显示在未明确指定某个其他值时,关键字参数具有的值。
print语句中的end参数有一个常见用法,即允许多个print构建单行输出。例如:
print("The answer is", end=" ")print(3 + 4)
产生单行输出:
The answer is 7
注意,第一个print语句的输出如何以空格(" ")而不是行末字符结束,第二个语句的输出紧跟在空格之后。
4 赋值语句
Python中最重要的语句之一是赋值语句。我们在前面的例子中已经看到了一些。
简单赋值
基本赋值语句具有以下形式:
<variable> = <expr>
这里variable是一个标识符,expr是一个表达式。赋值的语义是,右侧的表达式被求值,然后产生的值与左侧命名的变量相关联。
下面是我们已经看到的一些赋值:
x = 3.9 * x * (1 - x)fahrenheit = 9 / 5 * celsius + 32x = 5
变量可以多次赋值。它总是保留最新赋的值。下面的交互式Python会话展示了这一点:
>>> myVar = 0>>> myVar0>>> myVar = 7>>> myVar7>>> myVar = myVar + 1>>> myVar8
最后一个赋值语句展示了如何使用变量的当前值来更新它的值。在这个例子中,我只是对以前的值加1。记住,变量的值可以改变,这就是为什么它们被称为变量的原因。
有时,将变量看作计算机内存中的一种命名的存储位置是有帮助的,我们可以在其中放入一个值。当变量更改时,旧值将被删除,并写入一个新值。图1展示了用这个模型来描绘x = x + 1的效果。这正是赋值在某些计算机语言中工作的方式。这也是查看赋值效果的一种非常简单的方式,你会在整本书中看到类似这样的图片。
图1 x = x + 1的视图,变量就像盒子
Python赋值语句实际上与“变量盒子”模型略有不同。在Python中,值可能最终放在内存中的任何位置,而变量用于引用它们。对变量赋值就像把一个黄色小粘贴便签放在值上,并说“这是x”。图2给出了一个更准确的Python赋值的效果。箭头用于显示变量引用的值。请注意,旧值不会被新值擦除,变量只需切换到引用新值。效果就像将粘贴便签从一个对象移动到另一个对象一样。这是赋值在Python中实际工作的方式,所以你会看到这样一些粘贴便签样式的图片散布在本书中。
图2 x = x + 1的(Python)视图,变量就像便签
顺便说一句,即使赋值语句不直接导致变量的旧值被擦除和覆盖,你也不必担心计算机内存中充满“被丢弃”的值。如果一个值不再被任何变量引用,它就不再有用。Python将自动从内存中清除这些值,以便空间可以用于存放新值。这就像检查你的衣柜,抛出没有粘贴便签标记的东西。实际上,这个自动内存管理的过程确实被称为“垃圾收集”。
赋值输入
输入语句的目的是从程序的用户那里获取一些信息,并存储到变量中。一些编程语言有一个特殊的语句来做到这一点。在Python中,输入是用一个赋值语句结合一个内置函数input实现的。输入语句的确切形式,取决于你希望从用户那里获取的数据类型。对于文本输入,语句如下所示:
<variable> = input(<prompt>)
这里的<prompt>是一个字符串表达式,用于提示用户输入。提示几乎总是一个字符串字面量(即引号内的一些文本)。
当Python遇到对input的调用时,它在屏幕上打印提示。然后,Python暂停并等待用户键入一些文本,键入完成后按<Enter>键。用户输入的任何东西都会存储为字符串。请考虑以下简单的交互:
>>> name = input("Enter your name: ")Enter your name: John Yaya>>> name'John Yaya'
执行input语句导致Python打印输出提示“Enter your name:”,然后解释器暂停,等待用户输入。在这个例子中,我键入John Yaya。结果,字符串“John Yaya”被记在变量name中。对name求值将返回我键入的字符串。
如果用户输入是一个数字,我们需要形式稍复杂一点的input语句:
<variable> = eval(input(<prompt>))
这里我添加了另一个内置的Python函数eval,它“包裹”了input函数。你可能会猜到,eval是“evaluate(求值)”的缩写。在这种形式中,用户键入的文本被求值为一个表达式,以产生存储到变量中的值。举例来说,字符串“32”就变成数字32。如果回头看看示例程序,到目前为止,你会看到几个例子,我们像这样从用户那里得到了数字。
x = eval(input("Please enter a number between 0 and 1: "))celsius = eval(input("What is the Celsius temperature? "))
重要的是要记住,如果希望得到一个数字,而不是一些原始文本(字符串),需要对input进行eval。
如果你仔细阅读示例程序,可能会注意到所有这些提示结尾处的引号内的空格。我通常在提示的末尾放置一个空格,以便用户输入的内容不会紧接着提示开始。放上空格可以让交互更容易阅读和理解。
虽然我们的数字示例特别提示用户输入数字,但在这个例子中,用户键入的只是一个数字字面量,即一个简单的Python表达式。事实上,任何有效的表达式都是可接受的。请考虑下面与Python解释器的交互:
>>> ans = eval(input("Enter an expression: "))Enter an expression: 3 + 4 * 5>>> print(ans)23>>>
这里,提示输入表达式时,用户键入“3 + 4 * 5”。Python对此表达式求值(通过eval),并将值赋给变量ans。打印时,我们看到ans的值为23,与预期一样。在某种意义上,input-eval组合就像一个延迟的表达式。示例交互产生完全相同的结果,就像我们简单地写成ans = 3 + 4 * 5一样。不同的是,表达式由用户在语句执行时提供,而不是由程序员在编程时输入。
注意:eval函数功能非常强大,也有“潜在的危险”。如本例所示,当我们对用户输入求值时,本质上是允许用户输入一部分程序。Python将尽职尽责地对他们输入的任何内容求值。了解Python的人可以利用这种能力输入恶意指令。例如,用户可以键入记录计算机上的私人信息或删除文件的表达式。在计算机安全中,这被称为“代码注入”攻击,因为攻击者将恶意代码注入正在运行的程序中。
作为一名新程序员,编程给自己个人使用,计算机安全不是很大的问题。如果你坐在一台运行Python程序的计算机前面,你可能拥有对系统的完全访问权限,并且可以找到更简单的方法来删除所有文件。然而,如果一个程序的输入来自不受信任的来源,例如来自互联网上的用户,使用eval可能是灾难性的。
同时赋值
有一个赋值语句的替代形式,允许我们同时计算几个值。它看起来像这样:
<var1>, <var2>, ..., <varn> = <expr1>, <expr2>, ..., <exprn>
这称为“同时赋值”。语义上,这告诉Python对右侧所有表达式求值,然后将这些值赋给左侧命名的相应变量。下面是一个例子:
sum, diff = x+y, x-y
这里,sum得到x和y的和,diff得到x和y的差。
这种形式的赋值初看很奇怪,但实际上非常有用。这里有一个例子:假设有两个变量x和y,你希望交换它们的值。也就是说,你希望将当前存储在x中的值存储在y中,将当前存储在y中的值存储在x中。首先,你可能认为这可以通过两个简单的赋值来完成:
x = yy = x
这不行。我们可以一步一步地跟踪这些语句的执行,看看为什么。
假设x和y开始的值是2和4。让我们检查程序的逻辑,看看变量是如何变化的。以下序列用注释描述了在执行这两个语句时变量会发生什么:
# 变量 x y# 初始值 2 4x = y# 现在是 4 4y = x# 最后是 4 4
看到第一个语句将y的值赋给x,从而修改了x的原始值吗?当我们在第二步将x的值赋给y时,最终得到了原始y值的两个副本。
完成交换的一种方法是引入一个附加变量,它暂时记住x的原始值。
temp = xx = yy = temp
让我们来看看这个序列是如何工作的。
# 变量 x y temp# 初始值 2 4 暂时无值temp = x# 2 4 2x = y# 4 4 2y = temp# 4 2 2
从x和y的最终值可以看出,在这个例子中,交换成功。
这种三变量交换的方式在其他编程语言中很常见。在Python中,同时赋值语句提供了一种优雅的选择。下面是更简单的Python等价写法:
x, y = y, x
因为赋值是同时的,所以它避免了擦除一个原始值。
同时赋值也可以用单个input从用户那里获取多个数字。请考虑下面的程序,它求出考试平均分:
# avg2.py# A simple program to average two exam scores# Illustrates use of multiple inputdef main(): print("This program computes the average of two exam scores.") score1, score2 = eval(input("Enter two scores separated by a comma: ")) average = (score1 + score2) / 2 print("The average of the scores is:", average)main()
该程序提示用逗号分隔两个分数。假设用户键入86,92。input语句的效果就像进行以下赋值:
score1, score2 = 86, 92
我们已经为每个变量获得了一个值。这个例子只用了两个值,但可以扩展到任意数量的输入。
当然,我们也可以通过单独的input语句获得用户的输入:
score1 = eval(input("Enter the first score: "))score2 = eval(input("Enter the second score: "))
某种程度上,这可能更好,因为单独的提示对用户来说信息更准确。在这个例子中,决定采用哪种方法在很大程度上是品位问题。有时在单个input中获取多个值提供了更直观的用户接口,因此在你的工具包中,这是一项好技术。但要记住,多个值的技巧不适用于字符串(非求值)输入,如果用户键入逗号,它只是输入字符串中的一个字符。逗号仅在随后对字符串求值时,才成为分隔符。
确定循环
你已经知道,程序员用循环连续多次执行一系列语句。最简单的循环称为“确定循环”。这是会执行一定次数的循环。也就是说,在程序中循环开始时,Python就知道循环(或“迭代”)的次数。例如,前面介绍的chaos程序用了一个总是执行10次的循环:
for i in range(10): x = 3.9 * x * (1 - x) print(x)
这个特定的循环模式称为“计数循环”,它用Python的for语句构建。在详细分析这个例子之前,让我们来看看什么是for循环。
Python的for循环具有以下一般形式:
for <var> in <sequence>: <body>
循环体可以是任意Python语句序列。循环体的范围通过它在循环头(for <var> in <sequence>:部分)下面的缩进来表示。
关键字for后面的变量称为“循环索引”。它依次取sequence中的每个值,并针对每个值都执行一次循环体中的语句。通常,sequence部分由值“列表”构成。列表是Python中一个非常重要的概念,你将在后续节中了解更多。现在只要知道,可以在方括号中放置一系列表达式,从而创建一个简单的列表。下列交互示例有助于说明这一点:
>>> for i in [0, 1, 2, 3]: print(i)0123>>> for odd in [1, 3, 5, 7, 9]: print(odd * odd)19254981
你能看到这两个例子做了什么吗?依次使用列表中的每个值执行了循环体。列表的长度决定了循环执行的次数。在第一个例子中,列表包含4个值,即0至3,并且简单地打印了这些连续的i值。在第二个例子中,odd取前5个奇数的值,循环体打印了这些数字的平方。
现在,让我们回到这一节开始的例子(来自chaos.py)再看一下循环头:
for i in range(10):
将它与for循环的模板进行比较可以看出,最后一个部分range(10)必定是某种序列。事实上,range是一个内置的Python函数,用于“当场”生成一个数字序列。你可以认为range是一种数字序列的隐性描述。要明白range实际上做了什么,我们可以要求Python用另一个内置函数list,将range转换为一个简单的旧式列表:
>>> list(range(10)) # turns range(10) into an explicit list[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
你看到这里发生了什么吗?表达式range(10)产生数字0到9的序列。使用range(10)的循环等价于使用那些数字的列表的循环。
for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
一般来说,range(<expr>)将产生一个数字序列,从0开始,但不包括<expr>的值。如果你想一想,就会发现表达式的值确定了结果序列中的项数。在chaos.py中,我们甚至不关心循环索引变量使用了什么值(因为i没有在循环体中的任何位置引用)。我们只需要一个长度为10的序列,让循环体执行10次。
正如前面提到的,这种模式称为“计数循环”,它是使用确定循环的一种很常见的方式。如果你希望在程序中做一定次数的某些事,请用一个带有合适range的for循环。下面一个反复出现的Python编程习语,你需要记住:
for <variable> in range(<expr>):
表达式的值确定了循环执行的次数。索引变量的名称实际上并不重要,程序员经常使用i或j作为计数循环的循环索引变量。只要确保使用的标识符没有用于任何其他目的,否则你可能会不小心清除稍后需要的值。
循环的有趣和有用之处在于,它们改变程序“控制流”的方式。通常我们认为计算机是严格按顺序执行一系列指令。引入循环会导致Python退回去并重复执行一些语句。类似for循环的语句称为“控制结构”,因为它们控制程序其他部分的执行。
一些程序员发现,用图片的方式来思考控制结构是有帮助的,即所谓的“流程图”。流程图用一些框来表示程序的不同部分,并用框之间的箭头表示程序运行时的事件序列。图3用流程图描述了for循环的语义。
图3 for循环的流程图
如果你在理解for循环时遇到困难,可能会发现学习流程图很有用。流程图中的菱形框表示程序中的决定。当Python遇到循环头时,它检查序列中是否有项。如果答案为“是”,则循环索引变量被赋予序列中的下一项,然后执行循环体。一旦循环体完成,程序返回到循环头并检查序列中的下一个值。如果没有更多的项,循环就退出,程序移动到循环之后的语句。
示例程序:终值
我们用另一个编程过程的例子来结束本文。我们希望开发一个程序来确定投资的终值。我们将从对问题的分析开始。你知道存入银行账户的钱会赚取利息,这个利息随着时间的推移而累积。从现在起10年后,一个账户将有多少钱?显然,这取决于我们开始有多少钱(本金)以及账户赚多少利息。给定本金和利率,程序应该能够计算未来10年投资的终值。
我们继续制定程序的确切规格说明。记住,这是程序做什么的描述。输入应该是什么?我们需要用户输入初始投资金额,即本金。我们还需要说明账户赚多少利息。这取决于利率和计复利的频率。处理此问题的一种简单方法是让用户输入年度百分比率。无论实际利率和复利频率如何,年利率告诉我们一年内的投资收益。如果年利率为3%,那么100美元的投资将在一年的时间内增长到103美元。用户应如何表示年利率3%?有一些合理的选择。让我们假设用户提供一个小数,因此利率将输入为0.03。
这样就得到以下规格说明:
程序 终值输入 principal 投资于美元的金额。 APR 以十进制数表示的年度百分比利率。输出 投资10年后的终值。关系 一年后的价值由principal(1 + apr)给出。该公式需要应用10次。
接下来为程序设计一个算法。我们将使用伪代码,这样就可以阐明我们的想法而又不必担心Python的所有规则。对于我们的规格说明,算法看起来很简单。
打印介绍输入本金的金额(principal)输入年度百分比利率(apr)重复10次: principal = principal *(1 + apr)输出principal的值
如果你知道一些金融数学(或者只是一些基本代数)的知识,可能会意识到,在这个设计中并不一定要用循环。有一个公式可以利用乘幂一步算出终值。我在这里用了一个循环来展示另一个计数循环,另一个原因是这个版本适合进行一些修改,在本文末尾的编程练习中将讨论。无论如何,这个设计说明有时算法的计算方式可以让数学更容易。知道如何计算一年的利息,就让我们能计算未来任意年数的利息。
既然我们已经在伪代码中想明白了这个问题,现在该利用我们的Python新知识开发一个程序了。算法的每一行都转换为一条Python语句:
打印介绍(print语句,第2.4节)print("This program calculates the future value")print("of a 10-year investment.")输入本金的金额(数值input,第2.5.2节)principal = eval(input("Enter the initial principal: "))输入年度百分比利率(数值input,第2.5.2节)apr = eval(input("Enter the annual interest rate: "))重复10次:(计数循环,第2.6节)for i in range(10):计算principal = principal * (1 + apr)(简单赋值,第2.5.1节) principal = principal * (1 + apr)输出principal的值(print语句,第2.4节)print("The value in 10 years is:", principal)
该程序中的所有语句类型都已在本文中详细讨论过。如果有任何问题,请回头查看相关说明。特别要注意的是,计数循环模式用于应用10次利息公式。
就到这里了。下面是完成的程序:
# futval.py# A program to compute the value of an investment# carried 10 years into the futuredef main(): print("This program calculates the future value") print("of a 10-year investment.") principal = eval(input("Enter the initial principal: ")) apr = eval(input("Enter the annual interest rate: ")) for i in range(10): principal = principal * (1 + apr) print("The value in 10 years is:", principal)main()
注意,我添加了几个空行来分隔程序的输入、处理和输出部分。策略性地放置“空行”能让程序更具有可读性。
这就是我所举的例子,测试和调试是留给你的练习。
小结
本文介绍了开发程序的过程,以及实现简单程序所需的许多Python细节。下面是一些要点的快速小结。
编写程序需要一种系统的方法来解决问题,包括以下步骤。
1.问题分析:研究需要解决的问题。
2.程序规格说明:确定程序要做什么。
3.设计:用伪代码编写算法。
4.实现:将设计翻译成编程语言。
5.测试/调试:查找和修复程序中的错误。
6.维护:让程序保持最新,满足不断变化的需求。
许多简单的程序遵循输入、处理、输出(IPO)的模式。
程序由标识符和表达式构成的语句组成。
标识符是一些名称,它们以下划线或字母开头,后跟字母、数字或下划线字符的组合。Python中的标识符区分大小写。
表达式是产生数据的程序片段。表达式可以由以下部件组成:
字面量 字面量是特定值的表示。例如,3是数字3的字面量表示。
变量 变量是存储值的标识符。
运算符 运算符用于将表达式组合为更复杂的表达式。例如,在x + 3 * y中,使用了运算符+和*。
数字的Python运算符包括加法(+)、减法(-)、乘法(*)、除法(/)和乘幂(**)等常见的算术运算。
Python输出语句print将一系列表达式的值显示在屏幕上。
在Python中,使用等号(=)表示将值赋给变量。利用赋值,程序可以从键盘获得输入。Python还允许同时赋值,这对于利用单个提示获取多个输入值很有作用。
eval函数可用来对用户输入求值,但它是一种安全风险,不应该用于未知或不可信来源的输入。
确定循环是执行次数已知的循环。Python的for语句是一个循环遍历一系列值的确定循环。Python列表通常在for循环中用于为循环提供一系列值。
for语句的一个重要用途是实现计数循环,这是专门设计的循环,以便将程序的某些部分重复特定的次数。Python中的计数循环通过使用内置的range函数,来产生适当大小的数字序列。
判断对错
1.编写程序的最好方法是立即键入一些代码,然后调试它,直到它工作。
2.可以在不使用编程语言的情况下编写算法。
3.程序在写入和调试后不再需要修改。
4.Python标识符必须以字母或下划线开头。
5.关键词是好的变量名。
6.表达式由文字、变量和运算符构成。
7.在Python中,x = x + 1是一个合法的语句。
8.Python不允许使用单个语句输入多个值。
9.计数循环被设计为迭代特定次数。
10.在流程图中,菱形用于展示语句序列,矩形用于判断点。
多项选择
1.以下 项不是软件开发过程中的一个步骤。
a.规格说明 b.测试/调试 c.决定费用 d.维护
2.将摄氏度转换为华氏度的正确公式是 。
a. F = 9/5(C) + 32 b.F = 5/9(C) − 32
c. F = B2 − 4AC d.F = (212 – 32)/(100 – 0)
3.准确描述计算机程序将做什么来解决问题的过程称为 。
a.设计 b.实现 c.编程 d.规格说明
4.以下 项不是合法的标识符。
a.spam b.spAm c.2spam d.spam4U
5.下列 不在表达式中使用。
a.变量 b.语句 c.操作符 d.字面量
6.生成或计算新数据值的代码片段被称为 。
a.标识符 b.表达式 c.生成子句 d.赋值语句
7.以下 项不是IPO模式的一部分。
a.输入 b.程序 c.处理 d.输出
8.模板for <variable> in range(<expr>)描述了 。
a.一般for循环 b.赋值语句
c.流程图 d.计数循环
9.以下 项是最准确的Python赋值模型。
a.粘贴便签 b.变量盒子 c.同时 d.塑料尺
10.在Python中,获取用户输入通过一个特殊的表达式来实现,称为 。
a.for b.read c.同时赋值 d.input
讨论
1.列出并用你自己的语言描述软件开发过程中的六个步骤。
2.写出chaos.py程序(第1.6节),并识别程序的各部分如下:
圈出每个标识符。
为每个表达式加下划线。
在每一行的末尾添加注释,指示该行上的语句类型(输出、赋值、输入、循环等)。
3.解释确定循环、for循环和计数循环几个概念之间的关系。
4.显示以下片段的输出:
a.for i in range(5):
print(i * i)
b.for d in [3,1,4,1,5]:
print(d, end=" ")
c.for i in range(4):
print("Hello")
d.for i in range(5):
print(i, 2**i)
5.先写出一个算法的伪代码而不是立即投入Python代码,为什么是一个好主意?
6.除end之外,Python的print函数还支持其他关键字参数。其中一个关键字参数是sep。你认为sep参数是什么?(提示:sep是分隔符的缩写。通过交互式执行或通过查阅Python文档来检验你的想法)。
7.如果执行下面的代码,你认为会发生什么?
print("start")for i in range(0): print("Hello")print("end")
看看本文的for语句的流程图,帮助你弄明白。然后在程序中尝试这些代码,检验你的预测。
编程练习
1.一个用户友好的程序应该打印一个介绍,告诉用户程序做什么。修改convert.py程序(第2.2节),打印介绍。
2.在许多使用Python的系统上,可以通过简单地点击(或双击)程序文件的图标来运行程序。如果你能够以这种方式运行convert.py程序,你可能会发现另一个可用性问题。 程序在新窗口中开始运行,但程序一完成,窗口就会消失,因此你无法读取结果。在程序结束时添加一个输入语句,让它暂停,给用户一个读取结果的机会。下面这样的代码应该有效:
input("Press the <Enter> key to quit.")
3.修改avg2.py程序(第2.5.3节),找出三个考试成绩的平均值。
4.使用循环修改convert.py程序(第2.2节),让它在退出前执行5次。每次通过循环,程序应该从用户获得另一个温度,并打印转换的值。
5.修改convert.py程序(第2.2节),让它计算并打印一个摄氏温度和华氏度的对应表,从0℃到100℃,每隔10℃一个值。
6.修改futval.py程序(第2.7节),让投资的年数也由用户输入。确保更改最后的消息,以反映正确的年数。
7.假设你有一个投资计划,每年投资一定的固定金额。修改futval.py,计算你的投资的总累积值。该程序的输入将是每年投资的金额、利率和投资的年数。
8.作为APR的替代方案,账户所产生的利息通常通过名义利率和复利期数来描述。例如,如果利率为3%,利息按季度计算复利,则该账户实际上每3个月赚取0.75%的利息。请修改futval.py程序,用此方法输入利率。程序应提示用户每年的利率(rate)和利息每年复利的次数(periods)。要计算10年的价值,程序将循环10 * periods次,并在每次迭代中累积rate/period的利息。
9.编写一个程序,将温度从华氏温度转换为摄氏温度。
10.编写一个程序,将以千米为单位的距离转换为英里。1千米约为0.62英里。
11.编写一个程序以执行你自己选择的单位转换。确保程序打印介绍,解释它的作用。
12.编写一个交互式Python计算器程序。程序应该允许用户键入数学表达式,然后打印表达式的值。加入循环,以便用户可以执行许多计算(例如,最多100个)。注意:要提前退出,用户可以通过键入一个错误的表达式,或简单地关闭计算器程序运行的窗口,让程序崩溃。在后续图书节中,你将学习终止交互式程序的更好方法。
本文内容转载自网络,来源/作者信息已在文章顶部表明,版权归原作者所有,如有侵权请联系我们进行删除!
填写下面表单即可预约申请免费试听! 怕学不会?助教全程陪读,随时解惑!担心就业?一地学习,可全国推荐就业!
Copyright © 京ICP备08000853号-56 京公网安备 11010802029508号 达内时代科技集团有限公司 版权所有
Tedu.cn All Rights Reserved