第2章
软件开发、数据类型和表达式
完成本章的学习之后,你将能够做到以下几点:
● 描述软件开发的基本阶段:分析、设计、编码和测试。
● 使用字符串作为终端输入和输出文本。
● 在算术运算中使用整数和浮点数。
● 构造算术表达式。
● 初始化并使用具有适当名称的变量。
● 从库模块导入函数。
● 使用参数调用函数并适当地使用返回值。
●构造一个执行输入、计算和输出的简单Python 程序。
●使用文档字符串记录Python 程序。
本章首先讨论软件开发过程,然后是一个案例研究,通过这个案例我们将介绍程序的分析、设计、编码和测试等步骤。还将研究构成程序的基本元素,主要包括文本和数字的数据类型以及操纵它们的表达式。本章最后介绍简单程序中函数和模块的使用。
2.1 软件开发过程
编程比编写代码行要复杂得多,就像建造房屋比敲钉子要复杂得多一样。“复杂得多”包括组织和规划,以及编制这些计划的各种惯例。计算机科学家将计划和组织程序的过程称为软件开发。软件开发有几种方法,其中之一被称为瀑布模型。
瀑布模型由几个阶段组成:
1. 客户请求:在这一阶段,程序员会收到一份关于问题的广泛陈述,该问题有可能适用于计算机化的解决方案。这个步骤也称为用户需求阶段。
2. 分析:程序员决定程序将做什么。这有时被视为澄清问题规格的过程。
3. 设计:程序员决定程序如何完成任务。
4. 实现:程序员编写程序。这个步骤也称为编码阶段。
5. 集成:大型程序有许多部分。在集成阶段,这些部分被整合成一个平稳运行的整体,这通常不是一件容易的事情。
6. 维护:程序通常具有较长的寿命,软件的寿命约为5至15年。在此期间,需求会发生变化,会检测到错误,并会进行或小或大的修改。
瀑布模型的各个阶段如图2-1 所示。正如你所看到的,该图类似于瀑布,其中每个阶段的结果向下流动到下一个阶段。然而,在一个阶段检测到的错误通常要求开发人员备份和重做前一阶段的一些工作。维护期间所做的修改也需要备份到早期阶段。总而言之,这些阶段也被称为软件开发生命周期。
虽然图中描述了不同的阶段,但这并不意味着开发人员必须在编码之前分析和设计一个完整的系统。现代软件开发通常是增量的和迭代的。这意味着,分析和设计可能会产生一个粗略的草稿、骨架版本或系统原型,这些可用于编码阶段,然后在一些测试后备份到早期阶段,以填充更多的细节。然而,为了介绍这一过程,我们将这些阶段视为不同的阶段。
程序在第一次运行时很少像希望的那样工作,因此,它们应该接受广泛而仔细的测试。许多人认为测试是一项仅适用于实现和集成阶段的活动,然而,你应该仔细检查每个阶段的产出。记住,早发现的错误比晚发现的错误的成本要小得多。图2-2 说明了在不同阶段发现错误时修复错误的一些相对成本。这些不仅是财务成本,也是时间和劳动力的成本。
请记住,开发软件的成本并没有在各个阶段平均分摊,图2-3 所示是典型的百分比。
你可能认为实现花费的时间最多,因此成本最高。然而,如图2-3 所示,维护是软件开发中最昂贵的部分。通过仔细分析、设计和实现,可以降低维护成本。
当你阅读这本书并开始提高编程技能时,应该记住以下两点:
● 软件开发不仅仅是编写代码。
● 如果想降低软件开发的总体成本,就要编写易于维护的程序。这需要彻底的分析、仔细的设计和良好的编码风格。我们将在整本书中对编码风格做更多的论述。
■.练习
- 列出软件开发过程的四个阶段,并解释它们完成了什么。
- 杰克说,他不会费心进行分析和设计,而是直接开始编写程序。为什么这不是个好主意?
2.2 案例研究:所得税计算器
本书的大部分章节都包含说明软件开发过程的案例研究。对于小程序来说,这种方法似乎过于复杂,但是当程序变大时,它会扩展得很好。第一个案例研究开发了一个计算所得税的程序。
每年,几乎每个有收入的人都面临着计算所得税申报表的不愉快任务。但愿它能像本案例研究中建议的那样容易完成!我们从客户请求阶段开始。
-->请求
客户请求一个计算个人所得税的程序。
-->分析
分析经常要求程序员学习一些关于问题领域的东西,本例中指的就是相关的税法。为了简单起见,我们假设有以下税法规定:
●所有纳税人都被征收20% 的统一税率。
●所有纳税人都可以享受10 000 美元的标准扣除。
●对于每个受抚养人,允许纳税人额外扣除3000 美元。
● 总收入在输入时必须精确到便士。
● 所得税以十进制数表示。
分析的另一部分决定了用户必须提供什么信息。在本例中,用户需要输入的是总收入和家庭人数。该程序根据输入和税法计算所得税,然后显示所得税。图2-4 显示了拟建的终端界面。斜体字符表示用户输入,其余部分由程序打印。在这里,包含交互界面是一个好主意,因为它允许客户和程序员在双方都能理解的上下文中讨论程序的预期行为。
-->设计
在分析期间,我们指定了程序将要做什么。在下一阶段,即设计阶段,我们将描述程序如何执行,这通常包括编写算法。在第1 章中,我们展示了如何用普通英语编写算法。事实上,算法常常是用一种有点程式化的英文版本写的,称为伪代码。以下是所得税程序的伪代码:
虽然没有精确的规则来规范伪代码的语法,但是在伪代码中,应该尽量以清晰简洁的方式描述程序的基本元素。请注意,这个伪代码非常类似于Python 代码,因此到编码步骤的转换应该很简单。
-->实现(编码)
给定前面的伪代码,经验丰富的程序员现在会发现编写相应的Python 程序很容易。另一方面,对于初学者来说,编写代码可能是这个过程中最困难的部分。尽管按照大多数标准,接下来的程序很简单,但不要期望一开始就能理解其中的每一点。本章的其余部分解释
了关于编码的更多细节。
-->测试
所得税计算程序可以作为一个脚本在IDLE 窗口运行。如果没有语法错误,我们将能够键入一组输入并查看结果。然而,一次没有语法错误并输出正确的运行,只提供了关于程序正确性的轻微指示。只有经过彻底的测试才能说明程序正常工作。测试是一个深思熟虑的过程,需要程序员进行一些规划和训练。在第一次成功运行后,为了满足截止日期或者继续下一个任务,马上提交程序会容易得多。但是你的工作或用户的生活可能会受到马虎的软件测试的影响。
可以从IDLE 窗口轻松执行测试。程序员只需要将程序反复加载到外壳中,并输入不同的输入集。真正的挑战是提出一组能够揭示错误的输入。此时的错误也称为逻辑错误或设计错误,是意外的输出。
正确的程序会为任何合法的输入产生预期的输出。所得税计算器的分析并没有说明哪些输入是合法的,但是常识表明它们是大于或等于0 的数字。其中一些输入将产生小于0 的输出,但是我们现在假设这些输出是符合预期的。即使计算机上输入数字的范围有限,测试所有可能的输入组合也是不切实际的。挑战是找到一个更小的输入集,称为测试套件,从中我们可以得出结论——该程序很可能对所有输入都是正确的。在税收项目中,我们尝试输入0、1 和2 作为受抚养人的数量。如果程序能正确处理这些,我们可以假设它能正确处理较大的值。总收入的测试输入是一个等于标准扣除额的数字,以及这个数字的两倍(分别为10 000 和20 000 )。这两个值将显示最低预期税(0)和预期税小于或大于0 的情况。程序在两个输入的每个可能组合下运行。表2-1 显示了测试套件中输入和预期输出的可能组合。
如果代码中存在逻辑错误,那么使用这些数据几乎肯定会被捕获。请注意,负输出不被视为错误。我们将在下一章中看到如何防止这种计算。
2.3 字符串、赋值和注释
文本处理是迄今为止最常见的计算应用。电子邮件、文本消息、网页和文字处理都依赖和操纵由字符串组成的数据。本节介绍使用字符串输出文本和Python 程序文档。我们首先介绍一般的数据类型。
2.3.1 数据类型
在现实世界中,我们总是使用数据,而不用考虑使用的是哪种数据。例如,考虑这句话:“2007年,米凯拉为她在东枫树街24号的房子支付了12万美元。”这句话至少包括四项数据——名字、日期、价格和地址,但是你当然不必在说出这句话之前停下来想一想。你不必考虑名字只包含文本字符,日期和房价是数字,等等。然而,在计算机程序中使用数据时,我们确实需要记住自己使用的数据类型。我们还需要记住可以对特定数据做什么(可以对特定数据执行什么操作)。
在编程中,数据类型由一组值和一组可对这些值执行的操作组成。Python 中的字面量是指数据类型的值对程序员来说的样子。程序员可以在程序中使用字面量来提及数据值。当Python 解释器对字面量求值时,它返回的值就是字面量。表2-2 显示了几个Python 数据类型的示例字面量。
表2-2 中列出的前两种数据类型int和float被称为数字数据类型,因为它们代表数字。本章稍后将详细介绍数字数据类型。目前,我们先关注字符串。
2.3.2 字符串字面量
在Python 中,字符串字面量是用单引号或双引号引起来的字符序列。Python shell 的以
下代码显示了一些示例字符串:
最后两个字符串字面量(' ' 和"")表示空字符串。虽然不包含字符,但空字符串仍然是字符串。注意,空字符串不同于包含单个空格字符的字符串。双引号字符串对于包含单引号或撇号的字符串来说非常方便。下面是一个例子:
注意,print函数显示嵌套引号,但不显示封闭引号。如果使用单引号将字符串字面量引起来,则双引号也可以包含在字符串字面量中。
当你用Python 代码编写字符串字面量,并作为输出显示在屏幕上时,需要确定是将字符串作为单行还是多行段落输出。如果要将字符串作为单行输出,必须在同一行代码中包含全部字符串字面量(包括其开头和结尾引号),否则将发生语法错误。要输出包含多行的文本段落,可以对每行使用单独的print 函数调用。但是,将整个字符串字面量、换行符和所有内容包含在三个连续的引号(单或双)内以进行打印会更方便。以下代码展示了如何做到这一点:
注意,输出中的第一行恰好在代码第一行结束的地方结束。当你在Python shell 中计算不带print功能的字符串时,可以看到嵌入结果中的换行符n的字面量,如下所示:
2.3.3 转义序列
换行符n被称为转义序列。转义序列是Python 将特殊字符(如制表符、换行符和退格符)表示为字面量的方式。表2-3 列出了Python 中的一些转义序列。
因为反斜杠用于转义序列,所以它必须被转义为字符串中的字面量字符。因此,将显示单个字符。
2.3.4 字符串连接
可以使用串联运算符“+”连接两个或多个字符串以形成新的字符串。下面是一个例子:
而“”运算符允许你通过重复给定次数的另一个字符串来构建一个字符串。左操作数是字符串,右操作数是整数。例如,如果你希望字符串前面有10个空格,使用1个空格、运算符和数字10比手工输入10个空格更容易。下面的代码展示了使用和+运算符来实现这一结果:
2.3.5 变量和赋值语句
正如我们在第1 章中看到的,变量将名称与值相关联,从而便于以后在程序中记住和使用该值。为变量选择名称时,需要注意一些规则。例如,某些名称(如if 、def 和import)已保留用于其他目的,因此不能用于变量名。通常,变量名必须以字母或下划线(_)开头,并且可以包含任意数量的字母、数字或其他下划线。Python 变量名区分大小写,因此,变量WEIGHT 不同于变量weight 。Python 程序员通常使用小写字母作为变量名,但是在变量名由多个单词组成的情况下,变量名中的每个单词(第一个单词除外)通常都以大写字母开头。这使得变量名更容易阅读。例如,名称interestRate 比名称interestrate 稍微容易阅读一些。
程序员将全大写字母用于从不改变的值的变量名。这些变量被称为符号常数。所得税计算器案例研究中的符号常数示例有TAX RATE 和STANDARD DEDUCTION 。变量接收初始值,并且可以用赋值语句重置为新值。赋值语句最简单的形式如下:
如第1章所述,尖括号中的术语命名或描述Python 代码构造的一部分。因此,符号代表任何Python 变量名,例如totalIncome 或taxRate。符号代表任何Python 表达式,例如。
Python 解释器首先计算赋值符号右侧的表达式,然后将左侧的变量名绑定到该值。当变量名第一次发生这种情况时,被称为定义或初始化变量。请注意,“=”符号表示赋值,而不是相等。初始化变量后,表达式中变量名的后续使用称为变量引用。
当解释器在任何表达式中遇到变量引用时,它会查找相关联的值。如果名称在被引用时尚未绑定到值,Python 会发出错误信号。以下代码展示了变量及其引用的一些定义:
前两个语句将变量和初始化为字符串值。下一条语句引用这些变量,连接变量引用的值以构建新字符串,并将结果分配给变量(“连接”表示“黏合在一起”)。最后一行代码是对变量的简单引用,该变量返回其值。
变量在程序中有两个重要目的:帮助程序员跟踪随时间变化的数据,还允许程序员用简单的名字引用复杂的信息。任何时候,如果可以用一个简单的东西代替一个更复杂的东西,就可以让程序员更容易理解和维护程序。这种简化过程被称为抽象,这是计算机科学的基本思想之一。在这本书中,你将了解计算中使用的其他抽象,包括函数、模块和类。
聪明的程序员选择的名字让别人很容易知道数据的用途,这反过来又使程序更容易维护和排除故障。优秀的程序不仅能正确执行任务,而且读起来就像一篇文章,其中每个单词都被仔细地选择以向读者传达适当的意思。例如,一个为简单的利息贷款创建支付计划的程序可能会使用变量和。
2.3.6 程序注释和文档字符串
我们在关于字符串的这一节结束时讨论程序注释。注释是计算机忽略的一段程序文本,但它为程序员提供了有用的信息。至少,程序的作者可以在程序文件的开头包括自己的名字以及关于程序目的的简短声明。这种类型的注释称为文档字符串,是本节前面讨论过的多行字符串形式。下面的例子是开始一段程序的典型文档:
除了文档字符串,行尾注释也可以对程序进行说明。这些注释以符号# 开始,延伸到一行的末尾。如果代码的含义不明显的话,行尾注释可以解释变量的目的或者它所使用的策略。下面是一个例子:
在程序中,好的文档可能和可执行代码一样重要。理想情况下,程序代码是自我说明的,所以我们可以立即理解它。然而,程序经常会被他人阅读,甚至作者在几个月没有看到代码之后可能会发现自己的代码不可思议。诀窍是,避免注释含义清晰的代码,但是当代码本身可能无法提供足够清晰的含义时,用注释帮助那些一头雾水的读者。考虑到这个目的,做以下事情是一个好主意:
● 开始一段程序时,要陈述其目的等相关信息,这些信息将有助于指导程序员在未来某个日期修改程序。
● 在变量定义后,附上解释变量目的的注释。
● 在代码的主要部分之前,用简短的注释解释其目的。本章前面介绍的案例研究就是这样做的。
● 用注释来解释复杂或棘手的代码部分的工作原理。
■.练习
1.设变量x 为"dog",变量y 为"cat" 。写出下列操作返回的值:
2.使用嵌入的换行符在单独的一行内写一个包含你的名字和地址的字符串。然后,不使用换行符写一个相同的字符串字面量。
3.如何在字符串字面量中将包含的撇号作为字符?
4.当print 函数打印嵌入换行符的字符串字面量时会发生什么?
5.下列哪一个是有效的变量名?
6.说明程序文档的两个目的。
2.4 数字数据类型和字符集
计算机最初的应用是用来处理数字的。虽然文本和媒体处理最近变得越来越重要,但是在许多应用中数字仍然非常重要。在本节中,我们简要概述数字数据类型及其变体——字符集。
2.4.1 整数
正如你在数学中所学的,整数包括0、正整数和负整数。Python 程序中的整数字面量没有逗号,前导负号表示负值。虽然整数的范围是无限的,但是计算机的内存限制了最大正整数和最大负整数的数量。在许多编程语言中,int数据类型最常见的实现方式包括从-2 147 483 648(-231)到2 147 483 647(231-1)的整数。但是,Python 整数的大小要大得多,并且仅受计算机内存的限制。作为一项实验,尝试计算表达式,它将最大正int值提高到100 次方。你会看到一个包含很多行数字的数!
2.4.2 浮点数
数学中的实数由整数、小数点和小数部分组成,如π的值是3.1415…。实数具有无限精度,这意味着小数部分的数字可以永远延续下去。像整数一样,实数也有无限的范围。然而,因为计算机的内存不是无限大的,所以不仅限制了范围,也限制了实数的精度。Python 使用浮点数来表示实数,float 类型最常见的值的范围从大约-10308 到10308,精度为16 位。
浮点数可以用普通的十进制记数法或科学记数法来表示。科学记数法通常对表示非常大的数字很有用。表2-4 显示了用这两种记数法表示的相同的值。
2.4.3 字符集
一些编程语言对字符串和单个字符使用不同的数据类型。在Python 中,字符字面量看起来就像字符串字面量一样,属于字符串类型。为了体现本书的不同之处,我们使用单引号括住单个字符,使用双引号括住多个字符。因此,我们称‘H’为一个字符,“Hi!”为一个字符串,尽管在技术上它们都是Python 字符串。
正如你在第1章中所学到的,在真正的计算机上运行之前,程序中的所有数据和指令都被翻译成二进制数。为了支持这种转换,字符串中的每个字符都映射到一个整数值。这个映射在字符集中定义,其中包括ASCII 集和Unicode 集。(术语ASCII 代表美国信息交换标准代码。)20 世纪60 年代,最初的ASCII 集使用从0 到127 的整数对每个键盘字符和几个控制字符进行编码。控制字符的一个例子是Control + D ,它是终止shell 窗口的命令。随着新功能键和一些国际字符被添加到键盘上,20 世纪80 年代中期ASCII 集的大小增加了一倍,达到256 个不同的值。然后,当从英语以外的语言添加字符和符号时,20 世纪90 年代早期创建了Unicode 集来支持65 536 个值。Unicode 目前支持超过128 000 个值。
表2-5 显示了字符值到前128 个ASCII 码的映射。左列中的数字代表ASCII 码最左边的数字,而最上面一行中的数字是最右边的数字。因此,第8 行第2 列的字符R 的ASCII 码是82。
有些人可能会觉得在数字类型的讨论中包含字符很奇怪。然而,正如你所看到的,ASCII 字符集映射到一组整数。Python 的ord和chr函数分别将字符转换为数字ASCII 码,然后再返回。下面的代码使用这两个函数来探索ASCII 系统:
注意,'B' 的ASCII 码是序列中'A' 之后的下一个数字。这两个函数提供了一种方便的方式来将字母移动固定的距离。例如,如果你想将字母'A' 向右移三个位置,可以写作。
■.练习
-
哪种数据类型最适合用来表示以下数据值?
- 一年中的月数
- 圆的面积
- 现行最低工资
- 宇宙的大约年龄( 12 000 000 000年)
- 你的名字
- 解释数据类型int 和float 之间的差异。
-
用Python 的科学记数法写以下浮点数的值:
- 355.76
- 0.007 832
- 4.3212
- 参考表2-5 写出字符'$' 和'&' 的ASCII 值。
2.5 表达式
正如我们已经看到的,字面量会对自身进行求值,而变量引用会对变量的当前值进行求值。表达式提供了一种对数据值执行操作以生成其他数据值的简单方法。你之前看到了在表达式中使用的字符串。当在Python shell 提示符下输入时,将计算表达式的操作数,然后将其运算符应用于这些值以计算表达式的值。在本节中,我们将更详细地研究算术表达式。
2.5.1 算术表达式
算术表达式由操作数和运算符组成,这些操作数和运算符的组合方式是你在代数课程中已经熟悉的。表2-6 显示了几个算术运算符,并举例说明了如何在Python 代码中使用它们。
在代数中,你可能习惯于这样表示乘法:ab。然而,在Python 中,必须使用乘法运算符“”明确表示乘法,如ab。二进制运算符放在其操作数之间(例如ab),而一元运算符放在其操作数之前(例如-a)。在Python 中计算算术表达式时,你在代数中学习的优先规则同样适用:
● 幂运算具有最高的优先级,首先计算。
● 接下来,在乘法、除法和取余之前,进行一元求反计算。
● 乘法、除法、商和取余都要在加、减法之前进行计算。
● 在赋值之前,对加法和减法进行计算。
● 同等优先级的操作是左结合的,因此它们是从左到右计算的。幂运算和赋值运算是右结合的,因此这些运算的连续实例是从右向左计算的。
●可以使用括号更改运算的顺序。表2-7 显示了一些算术表达式及其值。
表2-7 的最后两行显示了除以0 的尝试,这将导致错误。这些表达式很好地说明了语法和语义之间的区别。语法是一套规则,用于在语言中构建格式良好的表达式或句子。语义是一组规则,允许智能体解释这些表达式或句子的含义。当一个表达式或句子的格式不正确时,计算机会产生语法错误。当表达式描述的动作无法执行时,即使该表达式在语法上是正确的,也会检测到语义错误。虽然表达式45/0和45%0在语法上是正确的,但是它们没有意义,因为计算智能体不能执行它们。当人类用自然语言交谈时,可以容忍各种语法错误和语义错误。相比之下,计算智能体不能容忍这些错误。
除了精确除法之外,当算术表达式的两个操作数都是相同的数字类型(int或float)时,得到的值也是该类型。当两个操作数属于不同类型时,结果值属于更通用的类型。注意,float型比int型更通用。商运算符/ / 产生整数商,而精确除法运算符/ 总是产生浮点数。因此,3//4结果为0,而3/4结果为.75。
虽然表达式中的间距对Python 解释器来说并不重要,但是程序员通常在每个运算符前后各插入一个空格,以便于阅读代码。通常,表达式必须在一行Python 代码上完成。当表达式变长或变复杂时,可以通过在当前行的末尾放置反斜杠字符来移动到新行。下面的例子展示了这种方法:
确保在运算符之前或之后插入反斜杠。如果在IDLE 中以这种方式换行,编辑器会自动正确缩进代码。
正如你将很快看到的,也可以在逗号后立即中断一长串代码,示例包括带有几个参数的函数调用。
2.5.2 混合模式算术和类型转换
你已经看到/ / 运算符如何产生整数结果,/ 运算符如何产生带有两个整数的浮点结果。当一个操作数是int而另一个是float时会发生什么?在使用手持式计算器时,你不会过多考虑混合整数和浮点数的问题。执行包含整数和浮点数的计算称为混合模式算术。例如,如果一个圆的半径为3,则计算面积如下:
Python 如何执行这种类型的计算?在对不同数字类型的操作数进行二进制运算时,在执行运算之前,较不通用的类型(int)会暂时自动转换为较通用的类型(float)。因此,在示例表达式中,数值9 在乘法之前被转换为9.0。
处理数字输入时,必须使用类型转换函数。类型转换函数是一个与它转换到的数据类型同名的函数。因为input函数返回一个字符串作为其值,所以在执行算术运算之前,必须使用函数int或float将字符串转换为数字,如下例所示:
表2-8 列出了一些常见的类型转换函数及其用途。
注意,int 函数通过截断而不是舍入到最近的整数,将浮点数转换为整数。截断简单地切断了数字的小数部分。round 函数将浮点数舍入到最近的整数,如下例所示:
类型转换的另一个用途是利用数字和其他字符串来构造字符串。例如,假设变量profit 指的是一个浮点数字,代表以美元和美分表示的金额。为了构建一个代表这个输出值的字符串,我们需要将$ 符号连接到profit 值。但是,Python 不允许将+ 运算符与字符串和数字一起使用:
为了解决这个问题,我们使用str 函数将profit 值转换为字符串,然后将这个字符串连接到$ 符号,如下所示:
Python 是一种强类型编程语言。解释器在运算符应用于所有操作数之前检查它们的数据类型。如果操作数的类型不合适,解释器会停止执行,并显示错误消息。这种错误检查可防止程序尝试做它不能做的事情。
■.练习
-
令 x=8,y=2 。写出以下表达式的值:
- x + y * 3
- (x + y) * 3
- x ** y
- x % y
- x / 12.0
- x // 6
-
令x = 4.66 ,写出以下表达式的值:
- round(x)
- int(x)
- Python 程序员如何将浮点值舍入到最近的整数值?
- Python 程序员如何将数值连接到字符串值?
- 假设变量x 的值为55,使用赋值语句将x 的值增加1。
2.6 函数和模块的使用
到目前为止,在本章中我们已经研究了两种操作表达式中数据的方法。可以对一个或多个操作数应用“+”等运算符来产生新的数据值。或者,可以用一个或多个数据值调用诸如round 之类的函数来产生新的数据值。Python 包含许多有用的函数,这些函数组织在称为模块的代码库中。在本节中,我们将研究函数和模块的使用。
2.6.1 调用函数:参数和返回值
函数是一个代码块,可以按名称调用它来执行任务。函数通常需要参数即特定的数据值来执行任务。当一个函数完成任务(通常是某种计算)时,可以将结果发送回程序中最初调用该函数的部分。将结果发送回程序的另一部分的过程称为返回值。
例如,函数调用round(6.5) 中的参数是值6.5,返回的值是7。当参数是表达式时,首先对其进行计算,然后将其值传递给函数进行进一步处理。例如,函数调用abs(4-5) 首先计算表达式4-5,然后将结果-1 传递给函数abs。最后,函数abs 返回值1。
函数调用返回的值可以在表达式和语句中使用。例如,函数调用print(abs(4-5)+3) 打印值4。
有些函数只有可选参数,有些函数有必要参数,有些函数同时有必要参数和可选参数。例如,round 函数有一个必要参数,即要舍入的数字。当仅用一个参数调用时,round 函数显示其默认行为,即返回小数部分为0 的最近整数。但是,当提供第二个可选参数时,该参数(一个数字)指示第一个参数应该舍入到的精确位置的数量。例如,round(7.563, 2) 返回
7.56。
要了解如何使用函数的参数,请参考shell 中函数的文档。例如,Python 的help 函数显示了关于round 的信息,如下所示:
传递给函数的每个参数都有特定的数据类型。编写涉及函数及其参数的代码时,需要记住这些数据类型。试图将错误数据类型的参数传递给函数的程序通常会产生错误。例如,不能取字符串的平方根,而只能取数字的平方根。同样,如果将函数调用放在期望不同于函数返回的操作数类型的表达式中,则会引发错误。如果你不确定与特定函数的参数关联的数据类型,请阅读文档。
2.6.2 math 模块
函数和其他资源被编码在称为模块的组件中。__builtin__ 模块中的abs 和round 等函数总是可以使用的,而程序员必须从定义它们的模块中显式导入其他函数。math 模块包括几个执行基本数学运算的函数。以下代码导入math 模块并列出其资源目录:
这个函数名列表包括一些我们熟悉的三角函数以及Python 对常数π和e 的最精确预算。
要使用模块中的资源,可以将模块的名称写为限定符,后跟一个点(. )和资源的名称。例如,要使用math 模块中的pi 值,可以编写以下代码:math.pi。以下代码使用此方法显示π值和2 的平方根:
如果需要,还可以使用help:
或者,可以通过输入help(math) 浏览整个模块的文档。函数help 使用模块自己的文档字符串及其所有函数的文档字符串来打印文档。
如果要频繁使用模块的几个资源,可以通过导入各个资源来避免在每个引用中使用限定符,如下所示:
程序员偶尔会导入一个模块的所有资源,在没有限定符的情况下使用。例如,语句from math import * 将导入math 模块的所有资源。
通常,首选导入资源的第一种方法(即仅导入模块的名称)。模块限定符的使用不仅提醒读者函数的目的,还帮助计算机区分同名的不同函数。
2.6.3 main 模块
在本章前面的案例研究中,我们展示了如何为Python 脚本编写文档。为了区别这个脚本和程序中的其他模块(可能有很多),我们称它为main 模块(主模块)。像任何模块一样,主模块也可以被导入。不是从终端提示符启动脚本,也不是从IDLE 将脚本加载到shell 中,而是从终端提示符启动IDLE,并将脚本作为模块导入。我们用taxform.py 脚本来实现这一点,如下所示:
导入主模块后,可以通过运行help 函数查看其文档:
2.6.4 程序格式和结构
现在是退后一步了解简单Python 程序的整体格式和结构的好时机。按照以下方式构造程序是一个好主意:
● 从介绍性注释开始,说明作者的姓名、计划的目的和其他相关信息。此信息应该是文档字符串的形式。
● 然后,包括执行以下操作的语句:
● 导入程序所需的任何模块。
● 初始化重要变量,适当地注释。
● 提示用户输入数据,并将输入数据保存在变量中。
● 处理输入以产生结果。
● 显示结果。
花点时间回顾一下本章开头案例研究中介绍的所得税项目。注意该程序如何符合这个基本组织结构。另外,请注意,程序的各个部分由空白(空行)分隔。记住,程序应该易于其他程序员阅读和理解,应该像散文一样适合阅读!
2.6.5 使用终端命令提示符运行脚本
到目前为止,在本书中,我们一直在IDLE 中开发和运行Python 程序。当一个程序的开发和测试完成后,可以将其发布给其他人在他们的计算机上运行。Python 必须安装在用户的计算机上,但是用户不需要IDLE 来运行Python 脚本。
运行Python 脚本的一种方法是打开终端命令提示符窗口。在运行Windows 10 的计算机上,单击任务栏上的“在此处键入搜索”框,键入“命令提示符”,然后单击列表中的“命令提示符”。在早期版本的Windows 中,单击“开始”按钮,选择“所有程序”,选择“附件”,然后选择“命令提示符”。在基于Macintosh 或UNIX 的系统上,你将看到一个终端窗口。Macintosh 上的终端窗口如图2-5 所示。
用户打开终端窗口后,必须导航或更改目录,直到提示显示已到达包含Python 脚本的目录。例如,假设名为taxform.py 的脚本在终端当前目录下的pythonfiles 目录中,图2-6 显示了更改到该目录并列出其内容的命令。
到达适当的目录后,用户可以通过在命令提示符下输入命令python3 scriptname.py 来运行脚本(小心:如果运行python 而不是python3,你可能会启动Python 2 的解释器,它不会运行本书中的所有程序)。图2-7 显示了这个步骤和taxform 脚本的运行。
所有Python 安装还提供了通过双击操作系统文件浏览器中的文件来启动Python 脚本的功能。在Windows 系统上,此功能是自动的,而在Macintosh 和基于UNIX 的系统上,则是.py 文件类型必须设置为使用Python 启动器应用程序启动。但是,以这种方式启动脚本时,命令提示符窗口会打开,显示脚本的输出,然后关闭。为了防止这种窗口问题,可以在脚本末尾添加一个input 语句,该语句会暂停,直到用户按下Enter 或Return 键,如下所示:
■.练习
- 解释函数及其参数之间的关系。
- math 模块包括一个pow 函数,它计算一个数字的给定的幂。第一个参数是数字,第二个参数是指数。编写一个代码段来导入这个函数并调用它来打印82 和54 的值。
- 解释如何显示给定模块中所有函数的目录。
- 解释如何显示给定模块中特定函数的帮助信息。
2.7 本章小结
● 瀑布模型按照几个阶段描述了软件开发过程。分析决定了软件会做什么。设计决定了软件将如何实现其目的。实现包括用特定编程语言对软件进行编码。测试和集成表明该软件在发布时完成了预期的工作。发布后,维护会定位并修复错误,并为软件添加新功能。
● 字面量是可以出现在程序中的数据值,它们对自己进行求值。
● 字符串数据类型用于表示输入和输出的文本。字符串是字符序列。字符串字面量用单引号或双引号引起来。两个字符串可以通过串联组合形成一个新字符串。
● 转义字符以反斜杠开头,表示特殊字符,如删除键和换行符。
● 文档字符串是由三个引号引起来的字符串,提供程序文档。
● 注释是一段代码,解释器不会对其进行求值,但是程序员可以阅读它来获取关于程序的信息。
●变量是引用值的名称。变量的值被初始化,可以通过赋值语句重置。在Python 中,任何变量都可以被命名为任何值。
●int 数据类型表示整数。float 数据类型表示浮点数。整数或浮点数的大小受计算机内存的限制,浮点数的精度也是如此。
● 算术运算符用于形成算术表达式。操作数可以是数字字面量、变量、函数调用或其他表达式。
●运算符按优先级排序。按降序排列为幂、求反、乘法(*、/ 和% 相同)、加法(+ 和-相同)和赋值。优先级较高的运算符在优先级较低的运算符之前进行计算。正常优先级可以被括号改变。
● 混合模式操作涉及不同数字数据类型的操作数。它们会产生更具包容性的数据类型的值。
● 输入后,类型转换函数可用于将一种类型的值转换为另一种类型的值。
● 函数调用由函数的名称及其参数组成。函数被调用时,会对参数进行求值,并将这些值传递给函数的代码进行处理。当函数完成工作时,它可能会将结果值返回给调用方。
●Python 是一种强类型语言。解释器检查表达式中所有操作数的类型,如果给定操作数不符合预期,则停止执行并出错。
● 模块是一组资源,例如函数定义。程序员通过从模块中导入资源来访问它们。
●当计算机无法执行请求的操作时,会出现语义错误,例如试图除以0。带有语义错误的Python 程序停止,并显示错误消息。
● 当一个程序运行到正常终止但产生了不正确的结果时,即存在逻辑错误。
2.8 复习题
-
程序员在软件开发的分析阶段会做什么?
- 用特定的编程语言对程序进行编码
- 编写解决问题的算法
- 决定程序将做什么并决定其用户界面
- 测试程序以验证其正确性
-
程序员必须用什么来测试程序?
- 所有可能的合法输入集
- 所有可能的输入集
- 一组合法输入
- 一组合理的合法输入
-
必须使用什么来创建多行字符串?
- 一对双引号
- 一对单引号
- 一对连续三个双引号
- 嵌入的换行符
-
用来开始行尾注释的是什么符号?
- / 符号
- # 符号
- % 符号
-
下列哪些运算符列表按优先级递减排序?
- +,*,**
- *,/,%
- **,*,+
-
表达式2 ** 3 ** 2 计算得到以下哪一个值?
- 64
- 512
- 8
-
表达式round (23.67) 计算得到以下哪一个值?
- 23
- 23.7
- 24.0
-
假设变量name 的值为33。在执行完name = name * 2 后,name 的值是多少?
- 35
- 33
- 66
- 编写一个import 语句,只从数学模块中导入函数sqrt 和log。
- dir 函数和help 函数的作用是什么?
2.9 编程项目
在接下来的每个项目中,你应该编写一个包含介绍性文档字符串的程序。该文档应该描述程序将做什么(分析)以及如何做(以伪代码算法的形式设计程序)。包括所有输入的适当提示,并适当标记所有输出。编写完程序后,一定要用一组合理的合法输入来测试它。
- 案例研究的所得税计算器程序输出一个浮点数字,该数字可能显示超过两位的精度。使用round 函数修改程序以在输出数字中显示最多两位精度。
- 如果知道边的长度,就可以计算立方体的表面积。编写一个程序,以边的长度(整数)作为输入,并打印立方体的表面积作为输出。
- “五星级复古录像带”商店出租VHS 磁带和DVD 给那些喜欢购买唱片集的鉴赏家。这家商店以每晚3 美元的价格租赁新视频,以每晚2 美元的价格租赁老歌。写一个程序,使公司的职员可以用它来计算客户视频租赁的总费用。该程序应该提示用户输入每种视频的数量,并输出总成本。
- 编写一个程序,以球体的半径(浮点数)为输入,然后输出球体的直径、周长、表面积和体积。
- 物体的动量是质量乘以速度。编写一个程序,接受物体的质量(千克)和速度(米每秒)作为输入,然后输出其动量。
- 运动物体的动能由公式KE =(1/2)mv2 给出(其中m 是物体的质量,v 是速度)。修改你在上一题中创建的程序,以便打印出物体的动能和动量。
- 编写一个程序,计算并打印一年中的分钟数。
- 光以3×108 米/ 秒的速度传播。光年是光束在一年内传播的距离。编写一个计算和显示光年值的程序。
-
编写一个程序,将公里数作为输入,并打印相应的海里数。使用以下近似值:
- 1公里代表北极和赤道之间距离的1/10000。
- 北极和赤道之间有90度,每度包含60分的弧。
- 1海里是一个弧的1分。
- 员工的周薪总额等于小时工资乘以正常工作时间的总数加上加班费。加班费等于加班总小时数乘以每小时工资的1.5 倍。编写一个程序,将小时工资、总正常时数和总加班时数作为输入,并显示员工的周薪总额。