第3章 程 序 结 构 结构化程序设计主要由顺序结构、选择结构、循环结构三种逻辑结构组成。1966年,计算科学家C.Bohm和G.Jacopini在数学上证明,任何程序都可以采用顺序、选择、循环三种基本结构实现。结构化程序设计具有以下特点: 一是程序内的每一部分都有机会被执行; 二是程序内不能存在“死循环”(无法终止的循环); 三是程序尽量保持一个入口和一个出口,程序有多个出口时,只能有一个出口被执行; 四是少用goto类语句。 3.1顺 序 结 构 图31顺序结构 顺序结构是一种有序结构,它依次执行各语句模块。如图31所示,顺序结构程序在执行完语句1指定的操作后,接着执行语句2,直到所有语句执行完成。常见的顺序语句有导入语句、赋值语句、输入输出语句和其他程序语句等。下面主要介绍前三种顺序语句。 3.1.1导入语句 1. 模块导入 Python中库、包、模块等概念本质上就是操作系统中的目录和文件。模块导入就是将软件包、模块、函数等程序加载到计算机内存,方便程序快速调用。 Python标准库模块繁多,如果一次性将全部模块都导入内存,这会占用很多系统资源,导致程序运行效率很低。因此,Python对模块和函数采用“加载常用函数,其他需用再导入”的原则。所有函数都通过API(Application Program Interface,应用程序接口)调用,本书提供了常用函数的调用方法和案例,其他标准函数的调用方法可以用函数help()查看,或者参考Python使用指南(见https://docs.python.org/3/library/index.html)。 Python程序中的函数有内置标准函数、导入标准函数、第三方软件包中的函数、自定义函数。内置函数(如print()、len( )、help()等)在Python启动时已经导入内存,无须再次导入; 大部分标准函数模块(如math、sys、time等)都需要先导入再调用; 第三方软件包中所有模块和函数都需要先安装,再导入和调用。 2. 模块绝对路径导入——import语句 导入语句import可以导入一个目录下的某个模块,模块绝对路径导入语法如下。 1 2import 模块名 import 模块名 as 别名# 绝对路径导入,导入软件包或模块 # 绝对路径导入,别名用于简化调用 (1) 以上“模块名”包括库、包、模块等名称。 (2) 同一模块导入多次只会执行一次,这防止了同一模块的多次执行。 (3) 绝对路径导入时,调用时采用点命名形式,如“模块名.函数名()”。 (4) 模块有哪些函数?函数如何调用?这些问题必须查阅软件包用户指南。 (5) 如果当前目录下存在与导入模块同名的.py文件,就会将导入模块屏蔽。 【例31】根据勾股定理a2+b2=c2,计算直角三角形边长。 案例分析: 用勾股定理求边长需要进行开方运算,这需要用到数学模块math。 1 2 3 4 5import math a = float(input('输入直角三角形第1条边长:')) b = float(input('输入直角三角形第2条边长:')) c = math.sqrt(a*a + b*b) print('直角三角形的第3条边长为:', c) # 导入标准模块——数学计算 # 输入边长,转换为浮点数 # 调用开方函数(需要写模块名math) # 打印计算值 >>> 输入直角三角形第1条边长:3 输入直角三角形第2条边长:4 直角三角形的第3条边长为: 5.0# 程序输出 程序说明: 程序第4行,函数math.sqrt()为点命名方法,math为数学模块,sqrt()为math模块的开方函数,它只能接受非负的实数。一个模块会有多个函数,标准函数的调用方法可以在Python shell窗口下用命令“help(函数名)”查看,如help(print)。 【例32】导入第三方软件包Matplotlib中的画图子模块pyplot。 1import matplotlib.pyplot# 导入第三方软件包——画图模块 案例分析: 执行D:\Python\Lib\sitepackages\matplotlib\pyplot.py程序,其中D:\Python\Lib\sitepackages\是软件包安装位置,这个路径在Python安装时已经设置好,无须重复说明; matplotlib是软件包名(子目录); pyplot是画图子模块名(文件)。 3. 函数相对路径导入——from…import语句 函数相对路径导入语法如下。 1 2from 模块名 import 函数名 from 模块名 import *# 函数相对路径导入,导入指定函数 # 导入模块中所有函数和变量(慎用) 相对路径导入时,“模块名”是软件包中的模块(文件)或者子模块,“函数名”是模块中定义的函数、类、公共变量(如pi)等,可以一次导入多个函数。 相对路径导入时,函数调用直接采用“函数名()”的形式,无须使用“模块名.函数名()”的格式。相对路径导入使用方便,缺点如下: 一是搞不清楚函数来自哪个模块; 二是容易造成同一程序中同名函数问题。 第 3 章 程序结构 Python应用程序设计(第2版) 【例33】导入标准库数学模块中的开方函数。 1 2 >>>from math import sqrt >>>sqrt(2) 1.4142135623730951 # 导入标准模块——导入math模块中的sqrt()函数 # 调用函数对2进行开方运算(不需要写模块名math) 【例34】用from…import导入模块中的几个函数,而不是导入所有函数。 1from math import sqrt, sin, cos, pi# 导入标准模块——导入数学模块中的函数和常量 案例分析: 语句导入了math模块中的sqrt()(开方)、sin()(正弦)、cos()(余弦)三个函数,以及math模块中定义的常量pi(圆周率,3.141592653589793)。 4. 对导入软件包取别名 导入软件包时,如果对包或模块取别名后,调用函数时书写会简化很多。 【例35】导入第三方绘图包Matplotlib中的pyplot模块,并取别名为plt; 导入第三方科学计算包NumPy,并取别名为np。程序输出如图32所示。 图32绘图程序输出 1 2 3 4 5 6import matplotlib.pyplot as plt import numpy as np t = np.arange(0., 5., 0.2) plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^') plt.show()# 导入第三方包——绘图包.绘图模块,别名为plt # 导入第三方包——科学计算模块,别名为np # 调用NumPy包中的arange()函数 # 调用时,用别名plt代替matplotlib.pyplot # 调用时,用别名plt代替matplotlib.pyplot >>># 程序输出见图3-2 程序说明如下: 软件包NumPy的安装方法参见1.1.4节。 程序第1行,matplotlib为第三方软件包名,pyplot为子模块名; matplotlib.pyplot表示只导入Matplotlib软件包中的绘图子模块pyplot,程序第5、6行需要用到pyplot模块中的函数plot()和show(); matplotlib.pyplot模块调用时可简写为plt(别名)。 程序第2行,numpy为导入软件包全部模块,NumPy包别名为np。 5. 语句import与from…import的区别 语句import相当于导入一个目录(绝对路径),这个目录下可能有很多模块,因此调用函数时,需要注明是哪个模块中的函数,如“模块名.函数名()”。 语句from…import相当于导入一个目录中的指定模块的指定函数,调用模块中的函数时直接使用“函数名()”就可以了,因为导入时指明了该函数所在模块。 语句from…import *是将一个模块中所有函数都导入进来。这种导入方式容易污染命名空间,应谨慎使用from…import *语句,避免程序中同名变量和同名函数的冲突。 3.1.2赋值语句 1. 变量赋值常规方法 将值传送给变量的过程称为赋值。赋值语句中的“值”可以是数字或字符串,也可以是表达式、函数等。变量的数据类型在首次赋值时产生。赋值语句语法如下。 1变量名 = 值或者表达式 赋值语句中,“=”是把等号右边的值或表达式赋给等号左边的变量名,这个变量名就代表了变量的值。 Python赋值语句不允许嵌套赋值; 不允许引用没有赋值的变量; 不允许连续赋值; 不允许不同数据类型用运算符赋值。试图这样做将触发程序异常。 【例36】错误的变量赋值方法。 1 2 3 4 5>>>x = (y=0) >>>print(y) >>>x=2, y=5 >>>s = '日期' + 2018 >>>2 + 3 = c # 异常,不允许赋值语句嵌套赋值 # 异常,不允许引用没有赋值的变量 # 异常,一行多句时不能用逗号分隔 # 异常,不允许不同数据类型用运算符赋值 # 异常,不允许赋值语句顺序颠倒 【例37】正确的变量赋值方法。 1 2 3 4 5>>>path = 'd:\test\03\' >>>pi = 3.14159 >>>s = pi * (5.0**2) >>>lst = ['张飞', '程序设计', 60] >>>b = True # 字符串赋值 # 浮点数赋值 # 表达式赋值 # 列表赋值 # 布尔值赋值 【例38】Python中,一个变量名可以通过重复赋值,定义为不同的数据类型。 1 2>>>ai = 1314 >>>ai = '一生一世' # 变量名ai赋值为整数 # 变量名ai重新赋值为字符串 2. 变量赋值的特殊方法 【例39】元组赋值可以一次赋多个值。 1 2 3 >>>T = 1, 2, 3 >>>x, y, z = T >>>T, x, y, z ((1, 2, 3), 1, 2, 3)# 元组赋值,允许一个变量赋多个值 # 元组T中的值按顺序赋给多个变量 # 输出元组 # T=(1, 2, 3),x=1,y=2,z=3 【例310】变量链式赋值方法。 1 2 3>>>n = 10; s = '字符' >>>x = y = k = 0 >>>x = y = student = {'姓名':'贾宝玉', '年龄':18} # 一行多句时,按顺序赋值 # 赋值从右到左:k=0,y=k,x=y # 允许变量重新赋值,并改变数据类型 【例311】变量增量赋值方法。 1 2 3>>>x = 1 >>>x += 1 >>>x *= 3# x=1(语义:将1赋值给变量名x) # x=2(语义:将x+1后赋值给x;等价于x=x+1) # x=6(语义:将x*3后赋值给x;等价于x=x*3) 4 5 6 7 8>>>x -= 1 >>>x %= 3 >>>s = '世界,' >>>s += '你好!' >>>s *= 2 # x=5(语义:将x-1后赋值给x;等价于x=x-1) # x=2(模运算,语义:将x除3取余数赋值给x) # s = '世界,'(语义:字符串赋值给变量名s) # s = '世界,你好!'(语义:字符串连接) # s = '世界,你好!世界,你好!'(语义:字符串重复) 【例312】变量交换赋值方法,变量交换在排序算法中应用很多。 1 2 3 4>>>x, y = 10, 20 >>>x, y = y, x >>>a, b = '天上', '人间' >>>a, b = b, a # 变量序列赋值(x=10,y=20) # 变量内容交换,x←y,y←x(x=20,y=10) # 变量序列赋值(a='天上',b='人间') # 字符串变量交换,a←b,b←a(a='人间',b='天上') 3. 赋值语句应用案例 【例313】求根方法1: 对方程44x2+123x-54=0求根(比较例324、例328)。 案例说明如下。 一元二次方程标准式: Ax2+Bx+C=0 一元二次方程判别式: Δ=B2-4AC 解: Δ<0时,无解; Δ=0时,x=B/(2A); Δ>0时,x1=-((B+Δ)/(2A)),x2=-((B-Δ)/(2A))。 1 2 3 4 5 >>>delta = 123**2 - 4*44*(-54) >>>x1 = (123 + delta**0.5)/(-2*44) >>>x2 = (123 - delta**0.5)/(-2*44) >>>print('方程根:x1=', x1) 方程根:x1= -3.18123904902659 >>>print('方程根:x2=', x2) 方程根:x2= 0.3857845035720447 # 符号(如Δ)用读音代替(如delta) # 计算方程根:x1=-((B+Δ)/(2A)) # 计算方程根:x2=-((B-Δ)/(2A)) 程序说明: 程序第2行,用指数运算开方,即delta**0.5= delta**(1/2)=delta。 3.1.3输入输出语句 输入是用户告诉程序需要的信息,输出是程序运行后告诉用户的结果,通常将输入输出简称为I/O。Python输入输出方式有字符串输入输出、图形用户界面输入输出、文件输入输出、网络输入输出等。字符串输入输出函数为input()和print()。 1. 用函数input()读取键盘数据 函数input()是一个内置标准函数,函数input()的功能是从键盘读取输入数据,并返回一个字符串。如果希望输入数据为整数,则需要用函数int()将输入的数据转换为整数; 如果希望输入数据为浮点数(实数),则需要用函数float()将数据转换为浮点数。 【例314】用函数input()读取键盘输入数据。 1 2 3 >>>s = input('请输入产品名称:') 请输入产品名称:计算机 >>>x1 = input('请输入一个整数:') 请输入一个整数:105 >>>x2 = int(input('请输入一个整数:')) 请输入一个整数:105# 从键盘读取字符串,赋值给变量s # 从键盘读取字符串,赋值给变量x1 # 变量x1='105',注意,105是字符串 # 将输入字符串转换为整数,赋值给x2 # 变量x2=105,注意,105已转换为整数 4 >>>x3 = float(input('请输入浮点数:')) 请输入浮点数:88.66 # 将输入字符串转换为浮点数,赋值给x3 # 变量x3=88.66 2. 用函数eval()读取键盘多个数据 【例315】用函数eval()从键盘读取多个数据。 1 2 >>>a, b, c = eval(input('请输入3个数字:')) 请输入3个数字:1,2,3 >>>x, y = eval(input('数字x= ')), eval(input('数字y= ')) 数字x= 1 数字y= 2# 同一行输入数据 # 数据之间用逗号分隔 # 分行输入数据 程序说明: 程序第1行,输入数据少于变量个数时,Python会异常退出。 3. 交互环境的打印输出 【例316】Python shell内置了打印功能,没有print()函数也可以打印输出。 1 2 >>>'程序'+'设计' '程序设计' >>>5200000+1314 5201314 # 打印输出字符串表达式 # 打印输出数字表达式 4. 用函数print()打印输出 函数print()是一个内置的打印输出函数,它不是向打印机输出数据,而是向屏幕输出数据(参见1.1.3节)。函数print()有多个参数,可以用来控制向屏幕的输出格式。 【例317】用函数print()打印输出。 1 2 3print(' \u20dd') print('~'*12) print('海上生明月,天涯共此时。')# 圆形符号的UTF8编码为\u20dd # 连续打印12个波纹字符串 # 打印字符串 >>>  ~~~~~~~~~~~~ 海上生明月,天涯共此时。# 程序输出 【例318】函数print()的打印输出方法。 1 2 3 4 >>>love = 5201314 >>>print('爱情计算值=', love) 爱情计算值= 5201314 >>>print('学号\t姓名\t成绩') 学号 姓名 成绩 >>>print('休言女子非英物\n夜夜龙泉壁上鸣') 休言女子非英物 夜夜龙泉壁上鸣# 变量赋值 # 输出提示信息和变量值 # 用制表符'\t'控制输出空格 # 注意,\t和\n只有在引号内才起作用 # 用换行符'\n'控制换行输出 5. 用占位符控制输出格式 字符按规定格式输出是一个经常遇到的问题。可以用%表示占位符,有几个%,后面就需要有几个变量顺序对应。常见的占位符有%d(整数)、%f(浮点数)、%s(字符串)、%x(十六进制整数)。不确定用什么占位符,参数%s永远起作用,它会把任何数据类型转换为字符串。占位符前面的x表示占几位,如10.2f表示占10位,其中小数占2位。 【例319】用占位符控制输出格式。 1 2 3 4 5 >>>s1='布衣中,'; s2='问英雄。' >>>'%s%s'%(s1, s2) '布衣中,问英雄。' >>>'您好, %s, 您有 %s 元到账了。' %('小明', 1000.00) '您好, 小明, 您有 1000.00 元到账了。' >>>print('教室面积是%10d平方米。' %(80)) 教室面积是 80平方米。 >>>print('教室面积是%10.2f平方米。' %(80)) 教室面积是 80.00平方米。# 定义字符串 # 参数%为占位符,s为字符串 # 第1个%s对应'小明',其余类推 # %10d为右对齐,占10位 # %10.2f为右对齐,占10位 # 其中小数占2位 6. 利用函数格式化输出 函数{:}.format()可以格式化输出,函数用{:}来代替占位符%,语法如下。 1{索引号:[填充字符] [对齐] [正负] [小数位] [宽度] [类型]}.format(元素) 参数“索引号”说明{:}中的参数在format()中的索引号,一般为0; 如果没有则以默认顺序自动分配。如'{0:*^10}'.format('说明')表示索引号为0,冒号是分隔符。 参数“填充字符”默认为空格,如'{:*^10}'表示用10个*号填空。 参数“对齐”有>(右对齐)、<(左对齐)、^(居中),如{0:<6}为右对齐,宽度为6位。 参数“正负”为是否保留正负号,+为正号,-为负号,如{:+.2f}为2位小数,保留+号。 参数“小数位”为指定小数的精确到第几位,如{:.2f}为精确到2位小数。 参数“宽度”为元素显示宽度位,如果前面加0,则表示用0填充。 参数“类型”为指定元素类型,如b为二进制,x为十六进制。 返回值: 函数返回格式化后的字符串。 【例320】函数{:}.format()的格式化输出方法。 1 2 3 >>>'{0:*^10}'.format('说明') '****说明****' >>>a = '孙悟空'; b = '猪八戒' >>>'{1}埋怨起{0}来'.format(a, b) '猪八戒埋怨起孙悟空来'# 0为索引号,:分为隔符,*为填空,^为居中对齐,10为宽度 # 注意,宽度包括元素字符,一个汉字为一个字符 # 索引号1对应元素b,索引号0对应元素a 【例321】Python 3.6以上版本对函数print()新增了一个f参数,它调用函数s.format()对字符串进行格式化输出,它可以将大括号内的变量替换为具体值。 1 2 3 >>>x = 100; y = 60; s = '优良' >>>print(f'考试学生有{x}个,成绩{s}的有{y}个。') 考试学生有100个,成绩优良的有60个。 >>>print(f'浮点数1/3的4位小数为{1/3:.4f}。') 浮点数1/3的4位小数为0.3333。# 变量赋值 # 参数f为字符串格式化输出 # 符号":.4f"为输出4位小数 说明: 程序第2行与print('考试学生有{}个,成绩{}的有{}个。'.format(x,s,y))语句等效。 3.2选 择 结 构 选择结构由if语句组成,它根据条件表达式的值选择程序执行方向。 条件选择语句是判断某个条件是否成立,然后选择执行程序中的某些语句块。与顺序结构比较,选择语句使程序的执行不再完全按照语句的顺序执行,而是根据某种条件是否成立来决定程序执行的走向,它体现了程序具有基本的逻辑判断功能。 条件选择语句有单条件选择结构(见图33)、双条件选择结构(见图34)、多条件选择结构(见图35)。条件选择语句有以下特征。 图33单条件选择结构 图34双条件选择结构 图35多条件选择结构 (1) 无论条件表达式的值为T(True),或者为F(False),一次只能执行一个分支方向的语句块。简单地说,程序不能同时执行语句块1和语句块2。 (2) 无论执行哪一个语句块,都必须能脱离选择结构(见图33~图35中c点)。 3.2.1单条件选择结构 单条件选择结构很简单,如果条件表达式为真,则执行语句块1,然后结束条件选择语句; 如果条件表达式为假,则直接结束条件选择语句(语句结构见图33)。由此可见,程序代码并不是全部都需要执行,选择语句使得程序具有了很大的灵活性。 【例322】单条件选择语句简单案例。 1 2 3x = 80 if x >= 60: print('成绩及格') # 变量赋值 # 条件选择语句,如果x>= 60为真 # 则执行本语句,执行完后结束if语句 >>>成绩及格# 程序输出 3.2.2双条件选择结构 双条件选择结构如图34所示,双条件选择语句的语法如下。 1 2 3 4if 条件表达式: 语句块1 else: 语句块2# 条件表达式只允许用关系运算符"==";不允许用赋值运算符"=" # 如果条件表达式为True,则执行语句块1,执行完后结束if语句 # 否则 # 如果条件表达式为False,则执行语句块2,执行完后结束if语句 在ifelse语句中,保留字if可以理解为“如果”; 条件表达式往往采用关系表达式(如x>=60),条件表达式的值只有True或者False; 语句结尾的冒号(:)可以理解为“则”; 保留字“else:”可以理解为“否则”。注意,if语句后的冒号(:)不可省略,if语句块可以有多行,但是if语句块内部必须缩进4个空格,并且保持垂直对齐。 Python根据条件表达式的值为True还是为False,来决定怎样执行ifelse语句中的代码。如果条件表达式的值为True,Python就执行if语句块1; 如果条件表达式的值为False,Python将忽略语句块1,选择执行语句块2。 【例323】双条件选择语句简单案例。 1 2 3 4 5x = 80 if x >= 60: print('成绩及格') else: print('成绩不及格') # 变量赋值 # 如果条件表达式x>= 60为真,则执行语句3 # 执行完本语句后,结束if语句(不执行语句4和语句5) # 否则执行语句5(x>= 60为假时,跳过语句3) # 执行完本语句后,结束if语句 >>>成绩及格# 程序输出 程序说明: 双条件选择程序结构适用于二选一的应用场景,两个语句块中总有一个语句块会被执行。如果有多种选择的要求,应当采用多条件选择语句结构。 【例324】求根方法2: 对方程44x2+123x-54=0求根(比较例313、例328)。 案例分析: Python可以用函数input()读取用户输入信息,但是Python默认将输入信息保存为字符串形式。所以,需要用函数float()将输入信息强制转换为浮点数类型,这样在计算时才可以避免出现错误。 1 2 3 4 5 6 7 8 9 10 11 12 13 14import math print('请输入方程A*x**2+B*x+C=0的系数:') a = float(input('二次项系数A = ')) b = float(input('一次项系数B = ')) c = float(input('常数项系数C = ')) p = b*b-4*a*c if p<0: print('方程无解') exit() else: x1 = (-b+math.sqrt(p))/(2*a) x2 = (-b-math.sqrt(p))/(2*a) print(f'x1={x1} x2={x2}')# 导入标准模块——数学计算 # 将输入数据转换为浮点数 # 计算方程判别式 # 如果判别式小于0 # 函数exit()为退出程序 # 计算方程根1 # 计算方程根2 # f参数为格式化输出 >>> 请输入方程A*x**2+B*x+C=0的系数: 二次项系数A = 44 一次项系数B = 123 常数项系数C = -54 x1= 0.3857845035720447 x2=-3.18123904902659 # 程序输出 三元运算是有三个操作数(左表达式值、条件表达式值、右表达式值)的程序语句。程序中经常用三元运算进行条件赋值,三元运算语法如下。 1a = 左表达式值 if 条件表达式值 else 右表达式值 三元运算语句中,首先进行条件判断,条件表达式的值为True时,将左表达式的值赋给变量; 条件表达式的值为False时,将右表达式的值赋给变量。 【例325】条件选择语句的三元运算。 1 2 3score = 80 s = '及格' if score >= 60 else '不及格' print('三元运算结果:', s) # 变量赋值 # 左表达式值为'及格',条件表达式值为True # 右表达式值为'不及格' >>>三元运算结果: 及格# 程序输出 3.2.3多条件选择结构 1. 多条件选择语句ifelif 当条件选择有多个项目时,可以使用多条件选择语句ifelif。elif是else if的缩写,语句结构如图35所示,多条件选择语句的语法如下。 1 2 3 4 5 6 7 8if 条件表达式1: 语句块1 elif 条件表达式2: 语句块2 elif 条件表达式3: 语句块3 else: 语句块4# 判断条件表达式1 # 若条件表达式1为True则执行语句块1,执行完后结束if-elif语句 # 若条件表达式1不满足,则继续判断条件表达式2 # 若条件表达式2为True则执行语句块2,执行完后结束if-elif语句 # 若条件表达式2也不满足,则继续判断条件表达式3 # 若条件表达式3为True则执行语句块3,执行完后结束if-elif语句 # 若条件表达式1、2、3都不满足(注意,此处没有条件表达式) # 执行语句块4,执行完后结束if-elif语句 以上语法中,if、elif都需要写条件表达式,但是else不需要写条件表达式; else、elif需要与if一起使用。注意,if、elif、else行尾都有英文冒号(:)。 ifelif语句从上往下判断,如果某个条件判断为True,将该条件选择对应的语句块执行完后,忽略剩下的elif和else语句块,结束ifelif语句,即一次只执行一个分支。 在单数据多条件选择编程时,开关语句switchcase比ifelif结构更简洁清晰。大多数程序语言都提供了switchcase条件选择语句或者极其相似的语句,如C/C++、Java、Go等静态语言都支持switchcase语句结构; Ruby、Shell、Perl语言中,也有类似的casewhen结构。其实在PEP275(2001年)、PEP3103(2006年)、PEP622(2020年)等标准中,讨论过引入switch开关语句,提出过几个switch语句的基本结构,然而核心开发者们似乎没有达成一致的共识,最终导致提案流产。 2. 多条件选择语句ifelif应用案例 【例326】BMI(Body Mass Index,体重指数)是国际上常用衡量人体健康程度的指标(见表31),过胖和过瘦都不利于身体健康。 表31BMI参考标准 BMI分类世界卫生组织标准中国参考标准相关疾病发病的危险性 体重过低BMI<18.5BMI<18.5低(其他疾病危险性增加) 正常范围18.5≤BMI<2518.5≤BMI<24平均水平 超重BMI≥25BMI≥24增加 肥胖前期25≤BMI<3024≤BMI<28增加 Ⅰ度肥胖30≤BMI<3528≤BMI<30中度增加 Ⅱ度肥胖35≤BMI<4030≤BMI<40严重增加 Ⅲ 度肥胖BMI≥40.0BMI≥40.0非常严重增加 BMI计算方法为: BMI=体重(kg)/身高2(m) 案例分析: 编程难点在于同时输出国际和国内对应的BMI分类。我们可以先对BMI指标进行分类,合并相同项,列出差别项,然后利用ifelif语句进行编程。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18height = eval(input('请输入您的身高(米):')) weight = eval(input('请输入您的体重(公斤):')) BMI = weight / (height**2) print('您的BMI为:{:.2f}'.format(BMI)) who = nat = '' if BMI < 18.5: who, nat = '偏瘦', '偏瘦' elif 18.5 <= BMI < 24: who, nat = '正常', '正常' elif 24 <= BMI < 25: who, nat = '正常', '偏胖' elif 25 <= BMI < 28: who, nat = '偏胖', '偏胖' elif 28 <= BMI < 30: who, nat = '偏胖', '肥胖' else: who, nat = '肥胖', '肥胖' print(f'国际BMI标准:{who}; 国内BMI标准:{nat}')# 输入数据 # 输入数据 # 计算BMI值 # 输出BMI值 # who为国际标准值 # nat为国内标准值 # 根据BMI值判断 # 多重判断 # 打印结论 >>> 请输入您的身高(米):1.75 请输入您的体重(公斤):76 您的BMI为:24.82 国际BMI标准:正常; 国内BMI标准:偏胖# 程序输出 3.2.4条件选择嵌套结构 在一个if语句块中嵌入另外一个if语句块称为if嵌套结构,语法如下。 1 2 3 4 5 6 7 8if 条件表达式1: 语句块1 if 条件表达式2: 语句块2 else: 语句块3 else: 语句块4# 开始外层if-else语句 # 开始内层if-else嵌套语句 # 结束内层if-else嵌套语句 # 结束外层if-else语句 【例327】用户输入一个整数,判断其是否能够被2或者3整除。 1 2 3 4 5 6 7 8 9 10 11num = int(input('请输入一个整数:')) if num % 2 == 0: if num %3 == 0: print('输入的数字可以整除2和3') else: print('输入的数字可以整除2,但不能整除3') else: if num % 3 == 0: print('输入的数字可以整除3,但不能整除2') else: print('输入的数字不能整除2和3') # if语句块1开始,%为模运算 # 内层if嵌套语句块2开始 # if语句块2部分 # 内层if嵌套语句块2结束 # if语句块1部分 # 内层if嵌套语句块3开始 # if语句块3部分 # if语句块3,语句块1结束 >>> 请输入一个数字:55 输入的数字不能整除2和3# 程序输出 程序说明: 第2~11行为if语句块1; 第3~6行为if语句块2; 第8~11行为if语句块3。条件嵌套结构的语句块难于理解,并且增加了程序测试的复杂度,应当尽量避免。 【例328】求根方法3: 对方程44x2+123x-54=0求根(比较例313、例324)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17import math a = float(input('请输入二次项系数a:')) b = float(input('请输入一次项系数b:')) c = float(input('请输入常数项系数c:')) if a != 0: delta = b**2-4*a*c if delta < 0: print('无根') elif delta == 0: s = -b/(2*a) print('唯一根x=', s) else : root = math.sqrt(delta) x1 = (-b+root)/(2*a) x2 = (-b-root)/(2*a) print(f'x1={x1} x2={x2}')# 导入标准模块——数学计算 # 将输入信息转换为浮点数 # 如果判别式不等于0 # 则计算方程判别式 # 如果判别式小于0 # 如果判别式等于0 # 则计算方程唯一根 # 计算方程判别式 # 计算方程根1 # 计算方程根2 # f参数为格式化输出 >>> 请输入二次项系数a:44 请输入一次项系数b:123 请输入常数项系数c:-54 x1= 0.3857845035720447 x2=-3.18123904902659 # 程序输出 3.3循 环 结 构 循环结构是重复执行一个或几个语句块(循环体),直到满足某一条件为止。循环是程序迭代的实现方法。Python有两种基本循环结构: 一种是计数循环,它用于循环次数确定的情况; 另一种是条件循环,它用于循环次数不确定的情况。 3.3.1计数循环 计数循环有序列循环(见图36)、迭代器循环(见图37)和列表推导式三种形式。 1. 序列循环 (1) 序列循环语法。序列可以是字符串、列表、元组、字典、集合等; 迭代变量用于接收序列中取出的元素。序列循环的功能是将序列中的元素逐个取出,每循环一次,迭代变量会自动接收序列中的一个元素,这相当于给迭代变量循环赋值,序列中最后一个元素取完后自动结束循环。序列循环的语法如下。 图36序列循环结构 图37迭代器循环结构 1 2for 迭代变量 in 序列: 循环体# 将序列中每个元素逐个代入迭代变量 说明: 迭代变量是临时变量,它的命名比较自由,如x、i、n、k、s、_(下画线)等。 (2) 序列循环案例。 【例329】列表为['唐僧','孙悟空','猪八戒','沙和尚'],逐个输出列表中的元素。 1 2 3names = ['唐僧', '孙悟空', '猪八戒', '沙和尚'] for x in names: print(x, end = ' ')# 定义列表(序列) # 列表names中的元素逐个代入迭代变量x # 执行循环体,参数end=' '为不换行 >>>唐僧 孙悟空 猪八戒 沙和尚# 程序输出 【例330】对字符串中的元素,用打字机效果逐个输出。 1 2 3 4 5 6 7 8 9import sys from time import sleep poem = '''\ pain past is pleasure. 过去的痛苦就是快乐。''' for char in poem: sleep(0.2) sys.stdout.write(char)# 导入标准模块——系统 # 导入标准模块——睡眠函数 # 加\不空行输出;删除\空1行输出 # 定义字符串 # 把poem中元素逐个代入迭代变量char # 睡眠0.2秒(用暂停形成打字机效果) # 输出字符串 >>> pain past is pleasure…# 程序输出(略) (3) 序列循环执行过程。 步骤1: 循环开始时,语句for内部计数器自动设置索引号=0,并读取序列(如列表等)中0号元素,如果序列为空,则循环自动结束并退出循环; 步骤2: 如果序列不为空,则for语句读取指定元素,并将它复制到迭代变量; 步骤3: 执行循环体内语句块,循环体执行完后,一次循环执行完毕; 步骤4: for语句内部计数器将索引号自动加1,继续访问下一个元素; 步骤5: for语句自动判断,如果序列中存在下一个元素,重复执行步骤2~5; 步骤6: 如果序列中已经没有元素了,则for语句会自动退出当前循环语句。 2. 迭代器循环 (1) 整数序列生成函数。函数range()用于生成顺序整数序列,语法如下。 1range(起始值,终止值,步长) 参数“起始值”默认从0开始,如range(5)等价于range(0,5),共5个元素。 参数“终止值”不包括本身,range()遵循“左闭右开”原则(取头不取尾)。 参数“步长”即每个整数的增量,默认为1,如range(5)等价于range(0,5,1)。 返回值: 函数range()返回一个[顺序整数列表]。 (2) 函数range()作为for循环的迭代器(生成整数序列),语法如下。 1 2for 迭代变量 in range(参数): 循环体# 将迭代器中的元素逐个赋值给"迭代变量" 【例331】一个球从100米高度自由落下,每次落地后反弹到原高度的一半再落下,球一共反弹了10次。输出每次反弹的高度,并计算球一共经过多少米路程。 案例分析: 设球反弹高度为high,每次为原高度的一半(high/2),总高度(total)为10次累计反弹高度。利用迭代循环将10次反弹高度进行累加(total += high)。 1 2 3 4 5 6 7high = 100 total = 0 for i in range(10): high /= 2 total += high print('球第', i+1, '次反弹高度:', high) print('球总共经过的路程为[米]:', total) # 高度赋值 # 总共经过路程 # 注意,range(10)一共循环10(0~9)次 # 计算反弹高度(反弹高度每次除以2) # 计算路程和(等价于total=total+high) # 注意,索引号i从0开始,因此需要+1 >>>球第 1 次反弹高度: 50.0…# 程序输出(略) (3) 遍历序列函数。函数enumerate()也可以作为for循环的迭代器,函数的基本功能是遍历一个序列,它通过迭代器来实现,内存使用量很低,运行速度快。函数语法如下。 1enumerate(序列, 索引号) 参数“序列”可以是列表、字符串、集合等。 参数“索引号”默认从0开始,也可以从指定编号开始(没有意义,见例332)。 返回值: 函数返回的迭代变量看上去是两个(如“索引号+元素值”),实际上是一个元组; 迭代变量也可以只有一个,如“索引号”或者“元素值”。 【例332】用函数enumerate()作为迭代器,循环打印列表元素。 1 2 3lst = ['智者', '乐水', '仁者', '乐山'] for x,y in enumerate(lst, 5): print(f'{x}:{y}')# 定义列表 # 两个迭代变量x和y,索引号从5开始 # 打印元素序列 >>> 5:智者 6:乐水 7:仁者 8:乐山# 程序输出 3. 列表推导式 列表推导式是将输出表达式(新列表)、for循环和if条件表达式封装在一个列表语句中的方法,它可以对源列表做映射或过滤等操作。列表推导式语法如下。 1 2变量名=[输出表达式 for 迭代变量 in 列表] 变量名=[输出表达式 for 迭代变量 in 列表 if 条件表达式]# 语法1 # 语法2 【例333】利用列表推导式生成一个等差数列列表。 1 2 3 >>>lst = [1, 2, 3, 4, 5, 6, 7, 8] >>>lst = [i*i for i in lst] >>>lst [1, 4, 9, 16, 25, 36, 49, 64]# 定义源列表 # 用源列表生成一个平方后的新列表(映射) # 输出新列表 【例334】成绩为[65,82,75,88,90],过滤出80~90的成绩(见图38)。 图38列表推导式执行过程示意图 1 2 3 >>>scores = [65, 82, 75, 88, 90] >>>lst = [s for s in scores if 80 <= s < 90] >>>print('成绩过滤新列表:', lst) 成绩过滤新列表: [82, 88]# 定义成绩列表 # 在[]内的语句为列表推导式(过滤) # 打印新列表 案例分析: 程序第2行的列表推导式看上去很复杂,难以理解,如果对复杂语句按子句逐个分解,理解起来就容易多了。如图38所示,列表推导式可以分为3个子句,子句1为列表循环,子句2为条件表达式(可选),子句3为输出表达式,各子句之间是嵌套关系。如图38所示,列表推导式的执行过程如下。 (1) 执行子句1,从源列表scores中取出第一个元素(65)。 (2) 子句2对取出的元素进行条件选择,这时条件值为假,继续循环取第2个元素(82); 这时条件值为真,将过滤出的元素存入子句3的表达式s中。 (3) 源列表所有元素循环判断完毕后,将子句3中的新列表赋值给变量lst。 3.3.2条件循环 条件循环有while条件循环(见图39)和while永真循环(见图310)两种结构。while条件循环在运行前先判断条件表达式,若条件表达式的值为True则继续循环,若条件表达式的值为False则退出循环。while永真循环则在循环开始设置条件为永真(True),然后在循环体内部设置条件判断语句,若条件表达式值为True则退出循环,否则继续循环。while永真循环广泛应用于事件驱动程序设计和游戏程序设计。 说明: 图310中,“if 条件表达式”语句可以设置条件为真退出循环,也可以设置条件为假退出循环,这里采用条件为真退出。while永真循环中,条件为真退出循环设计方法广泛用于GUI程序设计、游戏程序设计等。 图39while条件循环结构 图310while永真循环结构 while条件循环语法如下。 1 2while 条件表达式: 循环体# 如果条件表达式为True,则执行循环体 # 如果条件表达式为False,则结束循环 while永真循环语法如下。 1 2 3 4while True: 循环体 if 条件表达式: break# while永真循环 # 如果条件表达式为False,则继续循环 # 如果条件表达式为True,则强制退出循环 【例335】用while条件循环计算1~100的累加和。 1 2 3 4 5 6 7n = 100 sum = 0 counter = 1 while counter <= n: sum = sum + counter counter += 1 print(f'1到{n}之和={sum}')# 定义循环终止条件 # sum存放累加和,初始化变量 # 定义计数器变量,记录循环次数,并作为累加增量 # 循环判断,如果counter<=n为True,则执行下面语句 # 累加和(sum值+counter值后,再存入sum单元) # 循环计数(ounter<=n为False时结束循环) # 循环外语句,打印累加和 >>>1到100之和=5050# 程序输出 【例336】输出简单正三角形。 1 2 3 4i = 1 while i <= 5: print('*' * i) i += 1# 变量初始化 # 循环终止条件 # 打印*号 # 自加运算 >>> * ** *** **** ***** 【例337】输出简单倒三角形。 1 2 3 4i = 5 while i >= 0: print('*' * i) i -= 1# 变量初始化 # 循环终止条件 # 打印*号 # 自减运算 >>> ***** **** *** ** * 3.3.3中止和跳出循环 1. 循环中止: continue语句 在程序循环结构中,有时会需要跳过循环序列中的某些部分,然后继续进行下一轮循环(注意,不是终止循环)。这时可以用continue语句实现这个功能。 【例338】字符串为“人间四月芳菲尽”,在输出中跳过“芳”字。 1 2 3 4for s in '人间四月芳菲尽': if s == '芳': continue print(s,end=")# 循环取出字符串中的字符 # 判断字符串如果是'芳' # 则跳过这个字符,回到循环开始处重新循环 >>>人间四月菲尽# 程序输出 2. 强制跳出循环: break语句 在循环体中,可以用break语句强制跳出当前for或while循环体。break语句一般与if条件选择语句配合使用,在特定条件满足时,达到跳出当前循环体的目的。 【例339】字符串为“人间四月芳菲尽”,当遇到“芳”字时强制退出循环。 1 2 3 4for s in '人间四月芳菲尽': if s == '芳': break print(s,end=")# 循环取出字符串中的字符 # 判断字符串如果是'芳' # 则强制退出循环(比较与例3-38的区别) >>>人间四月# 程序输出 【例340】字典为{'宝玉': 85,'黛玉': 90,'宝钗': 88},根据输入的姓名(键),查找字典中对应的成绩(值),如果找到对应的成绩则结束程序,否则继续循环查找。 1 2 3 4 5 6 7 8 9dict1 = {'宝玉': 85, '黛玉': 90, '宝钗': 88} while True: key = input('请输入用户名:') if key in dict1: print(f'{key}的成绩是:', dict1.get(key)) break else: print('您输入的用户名不存在,请重新输入') continue# 定义字典 # 永真循环 # 输入姓名(键) # 判断字典中的键 # 打印查找到的值 # 强制退出循环 # 否则 # 返回循环开始处 >>>请输入用户名:# 程序输出 程序说明: 程序第5行,函数dict1.get(key)为获取字典中键对应的值,如果字典中不存在输入的key,则返回一个空值(None)。 注意,break语句是向下强制跳出循环; continue语句暂停向下执行,继续向上循环。程序中要谨慎使用break和continue语句: 一是它们本质上都是goto语句; 二是break语句造成了循环模块存在两个出口,这增加了程序测试的复杂度。 【例341】《石头—剪刀—布》游戏中,玩家赢则结束程序,否则游戏循环进行。 1 2 3import random lst = ['石头', '剪刀', '布']# 导入标准模块——随机数 # 定义字符串列表 4 5 6 7 8 9 10 11 12 13 14 15 16 17 win = [['布', '石头'], ['石头', '剪刀'], ['剪刀', '布']] while True: computer = random.choice(lst) people = input('请输入【石头,剪刀,布】:').strip() if people not in lst: people = input('请重新输入【石头,剪刀,布】:').strip() continue if computer == people: print('平手,再玩一次!') elif [computer, people] in win: print('电脑获胜!') else: print('你获胜啦!') break # 定义输赢标准 # while永真循环 # 生成随机数 # 玩家输入 # 判断输赢方 # 重新输入 # 回到循环起始处 # 判断输赢 # 用成员运算判断输赢 # 否则,玩家获胜 # 玩家获胜则退出循环 >>> 请输入【石头,剪刀,布】=石头 平手,再玩一次!# 程序输出 # 玩家输入"石头" 程序说明: 程序第8~17行为条件选择语句块,其中第15~17行为强制退出while永真循环。程序第13行,表达式“[computer, people] in win”为成员运算,它用来判断某一元素(如[computer, people])是否包含在变量中(如win)。 3.3.4程序的循环嵌套 循环嵌套就是一个循环体里面还有另外一个循环体,当两个以上的循环语句相互嵌套时,位于外层的循环结构简称为外循环,位于内层的循环结构简称为内循环。循环嵌套会导致代码的阅读性非常差,因此要避免出现三个以上的循环嵌套。 循环嵌套时,每执行一次外循环,都要进行一遍内循环。例如,读取一个8行5列的二维表格中的全部数据时,如果用循环遍历的方法读取表格内的数据,外循环1次时(读行),则内循环5次(读列),读取所有数据一共需要循环8×5=40次。 【例342】利用循环嵌套打印乘法口诀表。 案例分析: 用外循环控制打印行,内循环控制打印列。乘法口诀表不需要重复打印,因此内循环迭代变量从第1列开始,到j+1列结束(j为列数)。 1 2 3 4for i in range(1, 10): for j in range(1, i+1): print(f'{j}×{i}={i*j}\t', end='') print()# 外循环9次,打印9行(i行变量) # 内循环打印一行中的列(j列变量) # 按格式打印乘法口诀(\t为空格) # 换行 >>> # 程序输出 1×1=1 1×2=22×2=4 1×3=32×3=63×3=9 1×4=42×4=83×4=124×4=16 1×5=52×5=103×5=154×5=205×5=25 1×6=62×6=123×6=184×6=245×6=306×6=36 1×7=72×7=143×7=214×7=285×7=356×7=427×7=49 1×8=82×8=163×8=244×8=325×8=406×8=487×8=568×8=64 1×9=92×9=183×9=274×9=365×9=456×9=547×9=638×9=729×9=81 程序说明: 程序第1行,语句for i in range(1,10)为外循环,它控制行输出,共循环9次。 程序第2行,语句for j in range(1,i+1)为内循环,它控制一行中每个表达式(如1×1=1)的输出,由于迭代器为range(1,10),因此每行最多打印9个乘法口诀(9列)。 程序第3行,语句print()中,参数f为格式控制; {j}为乘数1; ×为乘号字符; {i}为乘数2,{i*j}为乘积; \t为水平制表符(即空格); end="为不换行打印。 程序第4行,语句print()属于外循环,因此语句缩进与第3行for语句对齐,外循环每次循环中,它会执行一次。语句print()中没有任何参数,它仅起到换行的作用。 【例343】输出1~100的素数。 案例分析: 公元前250年,古希腊数学家埃拉托色尼(Eratosthenes)提出了一个构造出不超过n的素数算法。它基于一个简单的性质: 对正整数n,如果用2~n的所有整数去除,均无法整除,则n为素数。n为内循环次数。 1 2 3 4 5 6 7import math for n in range(2, 101): for j in range(2, round(math.sqrt(n))+1): if n%j == 0: break else: print('素数为', n) # 导入标准模块——数学 # 外循环,0和1不是素数,n从2开始 # 内循环,j为2~sqrt(n)的整数 # 求余运算:n%j=0是合数(能整除) # 退出内循环,返回外循环 # 语句是for-else结构,不是if-else结构 # n%j≠0时,说明不能整除,n为素数 >>>素数为:2 3 5# 程序输出(略)(注:输出为竖行) 程序说明: 程序第3行,变量n为外循环迭代变量; 变量j为内循环迭代变量,值为2~sqrt(n)的整数; math.sqrt(n)为求n的开方值; round()为取整数; range()为定义顺序整数。 程序第4行,如果n和j求余为0,则n不是素数; 如果余数不为0,则n为素数。 程序第6行,语句else与第3行的for配套,语句含义是如果循环正常结束,则执行else中的代码; 如果循环中执行了break语句,则else中的代码将不再执行。 3.3.5案例: 用BBP公式求π值 BBP(由算法学家David Bailey、Peter Borwein、Simon Plouffe三人的姓名而得名)公式非常神奇,它可以计算圆周率中的任何一位。BBP公式如下。 π=∑∞k=0116k48k+1-28k+4-18k+5-18k+6 式中,k是π需要计算的小数位。公式的计算结果是十六进制数。虽然可以将十六进制数转换为十进制数,但是当把它转换为十进制数时,计算结果会被前后位数上的数所影响(二进制数没有影响)。 【例344】方法1: 利用BBP公式计算π值到小数点后第100位。 案例分析: 为了进行比较,从网络(http://pai.babihu.com/pi/100.html)查找到圆周率的100位小数准确值为: π=3. 1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679。 1 2 3 4 5N = int(input('请输入需要计算到小数点后第n位:')) pi = 0 for k in range(N): pi += 1/pow(16,k)*(4/(8*k+1)-2/(8*k+4)-1/(8*k+5)-1/(8*k+6)) print(f'小数点后第{N}位的pi值为:', pi)# 输入计算位数 # 初始化变量pi值 # 循环计算pi值 # BBP公式 # 打印计算结果 >>> 请输入需要计算到小数点后第n位:100 小数点后第100位的pi值为: 3.141592653589793# 程序输出 由以上程序输出结果可见,pi值只能精确到小数点后15位。可对程序进行修改,如例345所示。 【例345】方法2: 利用BBP公式计算π值到小数点后第100位。 案例分析: 对于浮点数的精确计算,需要用到Python标准函数库中的精确计算模块decimal,以及计算精度设置函数getcontext().prec。 1 2 3 4 5 6 7 8from decimal import Decimal, getcontext getcontext().prec = 102 N = int(input('请输入需要计算到小数点后第n位:')) pi = Decimal(0) for k in range(N): pi += Decimal(1/pow(16,k)*(4/(8*k+1)-2/(8*k+4)-1/(8*k+5)-1/(8*k+6))) print(f'小数点后第{N}位的pi值为:', pi)# 导入标准模块——精确计算函数 # 设精度为102位(很重要) # 输入计算位数 # 初始化pi值为精确浮点数 # 循环计算pi值 # BBP公式 # 打印pi值 >>> # 程序输出 请输入需要计算到小数点后第n位:100 小数点后第100位的pi值为:3.1415926535 8979320958 1689672085 3760862142 8145036074 3119042289 7105864764 2051543596 3184949209 0956344708 9 程序说明: 程序第3行,函数getcontext().prec为设置在后续运算中的有效位数。 程序第5行,函数Decimal(0)为设置参数0的精度为102位(默认28位)。参数可以为整数或者数字字符串(如'0'),但不能是浮点数,因为浮点数本身就不准确。 程序分析: 从以上计算结果可以看到,虽然可以计算到100位,但是小数点后第16位以后已经与网络查找的pi值不相符了。问题出在哪里呢?检查程序,可以发现N和k没有设置浮点数精确计算,N为循环计数序列,不设置精确值问题不大; 但是k是迭代变量,如果不设置浮点数精确计算,将导致浮点数精确计算失败。可对程序进行修改,如例346所示。 【例346】方法3: 利用BBP公式计算π值到小数点后第100位。 1 2 3 4 5from decimal import Decimal, getcontext getcontext().prec = 102 N = int(input('请输入需要计算到小数点后第n位:')) pi = Decimal(0) # 导入标准模块——精确计算函数 # 设计算精度为102位(很重要) # 输入计算位数 # 初始化pi值为精确浮点数 6 7 8 9 for n in range(N): k = Decimal(n) pi += Decimal(1/pow(16,k)*(4/(8*k+1)-2/(8*k+4)-1/(8*k+5)-1/(8*k+6))) print(f'小数点后第{N}位的pi值为:', pi) # 循环计算pi精确值 # 迭代变量为精确浮点数(很重要) # BBP公式 # 打印pi值 >>> # 程序输出 请输入需要精确到小数点后第n位:100 小数点后第100位的pi值为:3.1415926535 8979323846 2643383279 5028841971 6939937510 5820974944 5923078164 0628620899 8628034825 3421170679 8 # 校验计算结果正确 案例分析: 从例344、例345、例346三个程序,可以总结出以下经验。 (1) 一个优秀的程序需要反复调试,很难一次就设计成功。 (2) 例345程序运行正常,但是程序结果错误,说明程序的逻辑错误很难发现。 (3) 高精度浮点运算时,一定要注意迭代变量的积累误差。 习题3 31模块导入有哪些原则? 32说明语句import matplotlib.pyplot as plt各部分的功能。 33赋值语句应当注意哪些问题? 34编程: 从键盘输入三个随机整数,将这三个数由小到大排序输出。 35编程: 成绩≥85分用“优”表示; 75~84分用“良”表示; 60~74分用“及格”表示; 60分以下用“不及格”表示。从键盘输入一个成绩,显示成绩的等级。 36编程: 一对兔子从出生后第3个月起,每个月都生一对兔子,小兔子长到第3个月后,每个月又生一对兔子。假设兔子都不死,问9个月内每月兔子总数为多少? 37编程: “水仙花数”指一个三位数,各位数字立方和等于该数本身。如153是一个“水仙花数”,因为153=13+53+33。编程打印100~1000的所有“水仙花数”。 38编程: 用循环嵌套的方法,打印一个由*号组成的6行倒三角形。 39编程: 改写例341的程序,从键盘输入1时,代替汉字“石头”; 输入2时,代替汉字“剪刀”; 输入3时,代替汉字“布”; 输入q时退出游戏。 310编程: 列表为[55,85,73,94,42,88],将低于60的元素用“不及格”代替,大于或等于60的元素保留原值。用列表推导式编程,输出['不及格',85,73,94,'不及格',88]。