第3章 程 序 语 句 第3章程序语句 计算机程序之所以功能强大,主要在于程序具有逻辑推理能力,而最基本的逻辑推理操作是条件判断。条件判断可以控制程序执行的流程,因此程序控制结构非常重要。所有程序语言都提供顺序执行、条件判断执行(只执行某一部分程序块,如if语句)、循环执行(反复执行某一程序块,如for语句)三种最基本的程序控制方式。 3.1顺 序 语 句 3.1.1导入语句 1. 模块导入 Python中,库、包、模块等概念,本质上就是操作系统中的目录和文件。模块导入就是将软件包、模块、函数等程序一次性载入计算机内存,方便程序快速调用。 【例31】导入语句import matplotlib.pyplot实际上就是执行D:\Python37\Lib\sitepackages\matplotlib\pyplot.py程序。其中matplotlib是包名,pyplot是模块名。 Python程序以函数为主体,程序中有自定义函数、标准库函数、第三方软件包中的函数。程序中自定义函数无须导入。标准库函数分为两部分: 一部分内置函数(如print()、len()等72个内置函数)和内置方法(如str.format(),str.join()等45个内置方法),在Python启动时已经导入内存,无须再次导入; 另外的大部分标准库(如math、sys、time等模块)中的函数,都需要先导入再调用。第三方软件包中所有模块和函数都需要先导入再调用。导入语句一般放在程序开始部分,语法格式如下。 1 2 3 4 import 模块名 import 模块名 as 别名 from 模块名 import 函数名或子模块名 from 模块名 import * # 绝对路径导入,导入软件包或模块 # 绝对路径导入,别名为简化调用 # 相对路径导入,导入指定函数或子模块 # 导入模块所有函数和变量(慎用) (1) 以上“模块名”包括库、包、模块、函数等(可采用点命名形式)。 (2) 同一模块多次导入时,它只会执行一次,这防止了同一模块的多次执行。 (3) 绝对路径导入时,调用时用“模块名.函数名()”的形式,优点是避免了同名函数; 相对路径导入时,调用时用“函数名()”的形式,非常方便,缺点是容易导致同名函数。 (4) 一个函数库有哪些软件包?一个软件包有哪些模块?一个模块有哪些函数?某个函数如何调用(API,应用程序接口)?这些问题都必须参考软件包使用指南。 (5) 如果当前目录下存在与导入模块同名的.py文件,就会把导入模块屏蔽掉。 2. 模块路径查找 Python解释器执行import语句时,如果模块在当前路径中,模块马上就会被导入。如果需要导入的模块不在当前路径中,Python解释器就会查找搜索路径。搜索路径是Python在安装时设置的环境变量,安装第三方软件包时也会增加搜索路径。搜索路径存储在Python标准库中sys模块的path变量中。 【例32】查看sys模块中的搜索路径,了解Python设置了哪些路径。 1 2 >>>import sys >>>sys.path ['', 'D:\\Python37\\Lib\\idlelib', …(输出略) # 导入标准模块-系统功能 # 查看路径变量 # 输出当前路径设置 说明: 以上输出列表中,第一项是空串(''),它代表当前目录。 【例33】查看matplotlib.pyplot模块存放路径。 1 2 >>>import matplotlib.pyplot # 导入第三方包-绘图 >>>print(matplotlib.pyplot) # 查看模块存放路径 <module 'matplotlib.pyplot' from 'D:\\Python37\\lib\\site-packages\\matplotlib\\pyplot.py'> 【例34】用sys.path在路径列表中临时添加新路径d:\work\apps。 1 2 import sys sys.path.insert(0, 'd:\\work\\apps') # 导入标准模块-系统功能 # 添加新路径,0为路径插入在开始位置 说明: insert()函数是动态插入路径,作用范围仅限于当前.py文件。 3. import绝对路径导入 【例35】根据勾股定理a2+b2=c2,计算直角三角形的边长。 1 2 3 4 5 6 #E0305.py import math a = float(input('输入直角三角形第1条边的边长:')) b = float(input('输入直角三角形第2条边的边长:')) c = math.sqrt(a*a + b*b) print('直角三角形第3条边的边长为:', c) # 【计算三角形的边长】 # 导入标准模块-数学计算 # 输入边长,转换为浮点数 # 输入边长,转换为浮点数 # 调用数学开方函数计算边长 # 打印计算值 >>> 输入直角三角形第1条边的边长:3 输入直角三角形第2条边的边长:4 直角三角形第3条边的边长为: 5.0 # 程序运行结果 # 输入边长3 # 输入边长4 # 输出运行结果 程序第1行,每个模块都有各自独立的变量符号表(命名空间),导入模块(math)中的变量名会放入内存中模块符号表中。程序员可以放心地使用模块内部的全局变量,不用担心变量名的重名问题。使用该模块中的函数或属性时,必须加上模块名称。 程序第5行,math.sqrt()为调用math(数学)模块中的开方函数sqit()。注意,一个模块中往往会有多个函数,这些函数的调用方法(API)可以查看相关使用指南。 4. 对导入软件包或模块取别名 导入软件包时,对包或模块取别名后,调用模块时会简化很多。 【例36】对导入软件包或模块取别名示例。 1 2 3 4 5 6 7 #E0306.py import 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() # 【绘制散点曲线图A】 # 导入第三方包-绘图包.绘图模块(别名plt) # 导入第三方包-科学计算(别名np) # 调用科学计算包NumPy中的arange()函数 # 调用时,用别名plt代替matplotlib.pyplot # 调用时,用别名plt代替matplotlib.pyplot >>> 程序第2行,matplotlib为第三方软件包名,pyplot为子模块名; matplotlib.pyplot表示只导入了matplotlib软件包中的绘图子模块pyplot,因为程序第6、7行需要用到pyplot模块中的plot()和show()函数; matplotlib.pyplot模块在调用时可简写为plt(别名)。 程序第3行,numpy为导入软件包全部模块,numpy包别名为np。 【例37】程序与例36功能完全相同,语句差别是没有对软件包和模块取别名,因此调用这些包的函数时,要书写“包名.模块名.函数名()”的全称路径形式。 1 2 3 4 5 6 7 #E0307.py import matplotlib.pyplot import numpy t = numpy.arange(0., 5., 0.2) matplotlib.pyplot.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^') matplotlib.pyplot.show() # 【绘制散点曲线图B】 # 导入第三方包-绘图(没有别名) # 导入第三方包-科学计算(没有别名) # 调用numpy包时写全称 # 调用时写"包名.模块名.函数名" # 调用时写"包名.模块名.函数名" >>> 5. from相对路径导入 使用“from 模块名 import 子模块名”相对路径导入时,子模块名可以是软件包中的子模块,也可以是子模块中定义的函数、类、公共变量(如pi、e)等。 【例38】导入标准库中开方函数进行计算。 1 2 >>>from math import sqrt >>>sqrt(2) 1.4142135623730951 # 导入标准模块-导入math模块中的sqrt()函数 # 调用开方函数 【例39】采用“from...import”形式导入时,也可以使用别名(很少使用)。 1 2 >>>from math import sqrt as kf >>>kf(2) 1.4142135623730951 # 导入标准模块-导入sqrt函数,别名为kf(开方) 【例310】使用“from...import”导入模块中某几个函数,而不是所有函数。 from math import sqrt, sin, cos, log # 导入标准模块导入math模块中几个函数 6. “from 模块名 import *”导入 “from 模块名 import *”方式将导入模块中所有非下画线开始的对象,它可能导致命名空间中存在相同的变量名,这种导入方式容易污染命名空间,尽量谨慎使用。 3.1.2赋值语句 1. 变量赋值常规方法 Python是动态程序语言,不需要预先声明变量类型和变量长度,变量值和类型在首次赋值时产生。变量赋值很简单,取一个变量名然后给它赋值即可,语法格式如下。 变量名 = 表达式# 赋值语句的语法格式 赋值语句中,“=”是把等号右边的值或表达式赋给等号左边的变量名,这个变量名就代表了变量的值。 【例311】变量赋值的正确方法。 1 2 3 4 5 >>>path = 'd:\test\03\' >>>pi = 3.14159 >>>s = pi * (5.0**2) >>>s = ['张飞', '程序设计', 60] >>>b = True # 字符串赋值 # 浮点数赋值 # 表达式赋值 # 列表赋值 # 布尔值bool赋值 Python赋值语句不允许嵌套(重叠赋值); 不允许引用没有赋值的变量; 不允许连续赋值; 不允许数据类型混用: 否则将引发程序异常。 【例312】变量赋值的错误方法。 1 2 3 4 5 6 >>>x = (y=0) >>>print(y) >>>x=2, y=5 >>>x=2; y=5 >>>s = '日期' + 2018 >>>2 + 3 = c # 错误,不允许赋值语句嵌套 # 错误,不允许引用没有赋值的变量 # 错误,不允许连续赋值 # 可运行,但是PEP不推荐这种赋值方法 # 错误,不允许不同数据类型混淆赋值 # 错误,不允许赋值语句颠倒 【例313】Python中,一个变量名可以通过重复赋值,定义为不同的数据类型。 1 2 >>>ai = 1314 >>>ai = '一生一世' # 变量名ai赋值为整数 # 变量名ai重新赋值为字符串 2. 变量赋值的特殊方法 【例314】序列赋值实际上是给元组赋值,因此可以赋多个值,赋不同类型的值。 1 2 3 4 >>>A = 1, 2, 3 >>>x, y, z = A >>>n, m, k = 10, 6, 5 >>>n, m, k = 10, 0.5, '字符' # 序列赋值,允许一个变量赋多个值(实际为元组) # 元组A中的值顺序赋给多个变量 # 按顺序赋值为:n=10,m=6,k=5 # 按顺序赋值为:n=10,m=0.5,k='字符'(变量为元组) 【例315】变量链式赋值方法。 1 2 >>>x = y = k = 0 >>>x = y = student = {'姓名':'贾宝玉', '年龄':18} # 链式赋值,等价于x=0,y=0,k=0 # 允许变量重新赋值,并改变数据类型 【例316】变量增量赋值方法。 1 2 3 4 5 6 7 8 >>>x = 1 >>>x += 1 >>>x *= 3 >>>x -= 1 >>>x %= 3 >>>s = '世界,' >>>s += '你好!' >>>s *= 2 # x=1(语义:将1赋值给变量名x) # x=2(语义:将x+1后赋值给x;等价于x=x+1) # x=6(语义:将x*3后赋值给x;等价于x='***') # x=5(语义:将x-1后赋值给x;等价于x=x-1) # x=2(模运算,语义:将x除以3取余数赋值给x) # s = '世界,'(语义:字符串赋值给变量名s) # s = '世界,你好!'(语义:字符串连接) # s = '世界,你好!世界,你好!'(语义:字符串重复) 【例317】变量交换赋值方法。 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='天上') 【例318】对方程44x2+123x-54=0求根(方法1,比较例329、例333)。 一元二次方程标准式: 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 # 计算一元二次方程判别式Δ值 # 计算方程的根:x1=-((B+Δ)/2A) # 计算方程的根:x2=-((B-Δ)/2A) 3.1.3输入输出语句 输入是用户告诉程序所需要的信息,输出是程序运行后告诉用户的结果,通常把输入输出简称为I/O。Python有三种输入输出方式: 表达式、函数和文件。文件输入输出方式在后续章节专门讨论。input()和print()是最基本的输入和输出函数。 1. 用input()函数读取键盘数据 input()函数是一个内置标准函数,它的功能是从键盘读取输入数据,并返回一个字符串(注意,返回值不是数值)。如果希望输入的数据为整数,需要用int()函数将输入的数据转换为整数; 如果希望输入的数据为小数,需要用float()函数将输入的数据转换为小数; 也可以用eval()函数,将输入的数据转换为实数。 【例319】用input()函数读取键盘输入数据。 1 2 3 4 >>>s = input('请输入产品名称:') 请输入产品名称:计算机 >>>x = int(input('请输入一个整数:')) 请输入一个整数:105 >>>y = float(input('请输入一个浮点数:')) 请输入一个浮点数:88.66 >>>z = eval(input('请输入一个数字:')) 请输入一个数字:16.5 # 从键盘读取字符串,并且赋值给变量名s # 注意,即使输入的是数字,结果也是字符串 # 从键盘读取一个整数,赋值给变量名x # 注意,输入小数时会出错 # 从键盘读取一个小数,赋值给变量名y # 注意,输入会自动转换为浮点数 # 从键盘读取数字 # 注意,输入字符时会出错 2. 用eval()函数读取多个数据 【例320】用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 # 注意,输入个数少于 # 变量个数时会出错 # 分行输入数据 3. 表达式输出 【例321】表达式输出方法。 1 2 >>>'程序'+'设计' '程序设计' >>>5200000+1314 5201314 # 字符串表达式输出 # 数字表达式输出 4. 用print()函数输出 print()函数是一个内置的打印输出函数,它并不是向打印机输出数据,而是向屏幕输出数据。print()函数有多个参数,可以用来控制向屏幕的输出格式。 【例322】用print()函数连续打印输出。 1 2 3 print(" \u20dd") print("~"*12) print("海上生明月,天涯共此时。") # 打印符号(\u20dd为"明月"符号编码) # 连续打印12个"~"字符串 # 打印字符串 >>> ○ ~~~~~~~~~~~~ 海上生明月,天涯共此时。 # 程序运行结果 【例323】用prnt()函数输出的方法。 1 2 3 4 >>>love = 5201314 >>>print('爱情计算值=', love) 爱情计算值= 5201314 >>>print("学号\t姓名\t成绩") 学号姓名成绩 >>>print("休言女子非英物\n夜夜龙泉壁上鸣") 休言女子非英物 夜夜龙泉壁上鸣 # 变量赋值 # 输出提示信息和变量值 # 用制表符\t控制输出空格 # 注意,\t和\n只在引号内才起作用 # 用换行符\n控制换行输出 【例324】用print()函数连续输出不换行。 1 2 3 myList = ['碧云天', '黄花地', '西风紧', '北雁南飞'] for i in myList: print(' ', i, end='') # 列表赋值 # 循环输出列表 # 参数end=''为不换行输出 >>>碧云天黄花地西风紧北雁南飞 # 程序运行结果 5. 利用占位符控制输出格式 我们经常会遇到“亲爱的×××您好!您××月的电话费是××,余额是××”之类的字符串,其中×××的内容经常变化。所以,需要一种简便的格式化字符串方式。print()函数的输出格式可以用占位符控制。在字符串内部,%是占位符,有几个%,后面就需要几个变量或者值,顺序对应。占位符后的常见情况有d为整数、f为浮点数、s为字符串、x为十六进制整数。如果不太确定用什么占位符,%s永远起作用,它会把任何数据类型转换为字符串。占位符前面的x表示占几位,如10.2f表示占10位,其中小数占2位。 【例325】用占位符控制输出格式案例。 1 2 3 4 >>>'您好, %s, 您有 %s 元到账了。' %('小明', 1000.00) '您好, 小明, 您有 1000.00 元到账了。' >>>print('教室面积是%10d平方米。' %(80)) 教室面积是 80平方米。 >>>print('教室面积是%-10d平方米。' %(80)) 教室面积是80 平方米。 >>>print('教室面积是%10.2f平方米。' %(80)) 教室面积是 80.00平方米。 # %为占位符,s为字符串 # 第1个%s对应'小明',其余类推 # %10d=右对齐,占位符占10位 # %-10d=左对齐,占位符占10位 # %10.2f=右对齐,占位符占10位 # 其中小数占2位 6. 利用函数格式化输出 使用{:}.format()函数格式化输出,函数用{:}来代替占位符%。其语法格式如下。 {0:[填充字符] [对齐参数] [宽度]}.format() 对齐参数<为左对齐; 对齐参数^为居中; 对齐参数>为右对齐。 【例326】{:}.format()函数格式化输出方法。 1 >>>'{0:>10}'.format('计算机') '计算机' # 符号>为右对齐输出,10表示占10位,1个汉字算1位 2 3 4 5 6 >>>'{0:<10}'.format('计算机') '计算机' >>>'{0:^10}'.format('计算机') '计算机' >>>'{0:=^10}'.format('计算机') '===计算机====' >>>'{0:.4f}'.format(1/3) '0.3333' >>>'{:,}'.format(12369132698) '12,369,132,698' # 符号<为左对齐输出,10表示占10位 # 符号^为居中对齐输出,10表示占10位 # 符号=为填充符号,10表示填充10个"="符号 # 符号".4f"为4位小数输出 # 符号","为按千分位格式输出 3.2条件判断语句 3.2.1ifelse条件判断语句 程序设计中,经常需要根据特定条件来判断程序运行哪部分代码。在Python中,可以用if语句来检查程序当前状态,并根据当前状态采取相应的措施。因此,if语句和循环在编程语言中被称为“控制语句”,用来控制程序执行的顺序。 1. if语句语法格式 Python条件判断语句的语法格式如下: 1 2 3 4 if 条件表达式: 语句块1 else: 语句块2 # 条件表达式只允许用关系运算符"==";不允许用赋值运算符"=" # 如果条件为True,执行语句块1,执行完后结束if语句(不执行语句块2) # 否则 # 如果条件为False,执行语句块2,执行完后结束if语句(不执行语句块1) 在if语句中,关键词if可以理解为“如果”; 条件表达式往往就是关系表达式(如x>=60),条件表达式的值只有True或者False; 语句结尾的冒号(:)可以理解为“则”; 关键词“else:”可以理解为“否则”。注意,if语句的冒号(:)不可省略,if语句块可以有多行,但是if语句块内部必须缩进4个空格,并且保持垂直对齐。 Python根据条件表达式的值为True还是为False,来决定怎样执行if语句中的代码。如果条件表达式的值为True,Python就执行if语句块1; 如果条件表达式的值为False,Python将忽略语句块1,选择执行语句块2。由此可见,程序代码并不是全部都需要执行。这样就使得程序具有了很大的灵活性,为逻辑推理提供了良好基础。 值得注意的是,if语句中的“else: ”为可选语句块。 【例327】条件判断语句简单案例。 1 2 3 4 5 x = 80 if x >= 60: print('成绩及格') else: print('成绩不及格') # 变量赋值 # 条件判断语句,如果x>= 60为真 # 则执行本语句,执行完后结束if语句(不执行语句4和5) # 否则(x>= 60为假时,跳过语句3) # 执行本语句,执行完后结束if语句 程序第2行,如果x>=60条件成立(表达式的值为True),则执行语句3,执行完后结束if语句; 否则(表达式的值为False)跳过语句3,执行语句4和5,执行完后结束if语句。 2. 读取用户输入的数据进行条件判断 【例328】利用input()函数读取用户输入的数据。 1 2 3 4 5 num = input('请输入课程成绩:') if num > 59: print('不错,课程及格了!') else: print('成绩尚未及格,同学仍需努力!') # 数据输入语句 # 条件判断语句 >>> 请输入课程成绩:80 Traceback (most recent call last):…(输出略) # 程序运行结果 # 抛出异常信息 程序初学者很容易犯以上错误,这是因为input()函数返回的数据是字符串,而字符串不能与if表达式中的整数进行比较。 程序第1行,将原语句修改为: num = int(input('请输入课程成绩: ')),这样从键盘读取的数据通过int()函数转换为整数,就不会出现数据类型错误了。当然,如果输入的数据是浮点数或英文字符,同样会出现程序运行错误。 【例329】对一元二次方程44x2+123x-54=0求根(方法2,比较例318、例333)。 Python可以用input()函数读取用户输入信息,但是Python默认将输入信息保存为字符串形式。所以,需要用float()函数将输入信息强制转换为浮点数类型,这样在计算时才可以避免出现错误。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 #E0329.py import 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('x1=', x1, "\t", 'x2=', x2) # 【解一元二次方程B】 # 导入标准模块-数学计算 # 将输入数据转换为浮点数 # 计算方程判别式 # 如果判别式小于0 # 函数exit()为退出程序 # 计算方程的根1 # 计算方程的根2 # 参数"\t"=制表符(空4格) >>> 请输入方程A*x**2+B*x+C=0的系数: 二次项系数A = 44 一次项系数B = 123 常数项系数C = -54 x1= 0.3857845035720447x2= -3.18123904902659 # 程序运行结果 3. 三元条件判断语句 三元运算是有3个操作数(左表达式、右表达式、条件表达式)的程序语句。程序中经常用三元运算进行条件赋值,三元运算的语法格式如下。 a= 左表达式 if 条件表达式 else 右表达式 # 三元运算语法格式 三元语句中,条件表达式的值为True时,返回左表达式的值; 条件表达式的值为False时,返回右表达式的值; 返回值赋值在变量a中。 【例330】条件判断语句的三元运算。 1 2 3 score = 80 s = '及格' if score >= 60 else '不及格' print('三元运算结果:', s) # 操作数赋值 # 三元为:'及格'、score、'不及格' >>>三元运算结果: 及格 # 程序运行结果 3.2.2ifelif多分支判断语句 1. ifelif多分支判断语句语法 当条件判断为多个值时,可以使用多分支ifelif判断语句。elif是else if的缩写,ifelif语法格式如下。 1 2 3 4 5 6 7 8 if 条件表达式1: 条件1成立时,执行语句块1 elif 条件表达式2: 条件2成立时,执行语句块2 elif 条件表达式3: 条件3成立时,执行语句块3 else: 以上条件都不成立时,执行语句块4 在以上语法中,if、elif都需要写条件表达式,但是else不需要写条件表达式; if可单独使用,而else、elif需要与if一起使用。注意,if、elif、else行尾都有冒号(:)。 if语句执行有一个特点,它是从上往下判断的,如果某个判断的值是True,把该判断对应的语句块执行完后,就忽略掉剩下的elif和else语句块。 Python并不要求ifelif结构后面必须有else代码块。在有些情况下,else代码块很有用; 而在其他一些情况下,使用一条elif语句来处理特定情形更清晰。 2. ifelif多条件判断语句应用案例 【例331】体重是衡量一个人健康状况的重要标志之一,过胖和过瘦都不利于身体健康。BMI(身体质量指数)是国际上常用衡量人体健康程度的指标,其参考标准如表31所示。 表31BMI参考标准 BMI分类WHO标准中国参考标准NAT相关疾病发病的危险性 体重过低BMI<18.5BMI<18.5低(其他疾病危险性增加) 正常范围 18.5≤BMI<25 18.5≤BMI<24 平均水平 超重 BMI≥25 BMI≥24 增加 肥胖前期 25≤BMI<30 24≤BMI<28 增加 Ⅰ度肥胖 30≤BMI<35 28≤BMI<30 中度增加 Ⅱ度肥胖 35≤BMI<40 30≤BMI<40 严重增加 Ⅲ 度肥胖 BMI≥40.0 BMI≥40.0 非常严重增加 BMI计算方法为: BMI=体重/身高2,其中体重的单位为kg,身高的单位为m。 对于这个问题编程的难点在于同时输出国际和国内对应的BMI分类。我们可以先对BMI指标进行分类,合并相同项,列出差别项,然后利用ifelif语句进行编程。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 #E0331.py height = 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("国际BMI标准:'{0}',国内BMI标准:'{1}' ".format(who,nat)) # 【BMI计算】 # 输入数据 # 输入数据 # 计算BMI值 # 输出BMI值 # who为国际标准值 # nat为国内标准值 # 根据BMI值判断 # 多重判断 # 输出结论 >>> 请输入您的身高(米):1.75 请输入您的体重(公斤):76 您的BMI为:24.82 国际BMI标准:'正常', 国内BMI标准:'偏胖' # 程序运行结果 3.2.3if嵌套语句 在if嵌套语句中,可以把ifelifelse结构嵌套在另外一个ifelse结构中。 if嵌套语法格式如下: 1 2 3 4 5 6 7 8 9 10 if 条件表达式1: 语句块1 if 条件表达式2: 语句块2 elif 条件表达式3: 语句块3 else: 语句块4 else: 语句块5 # 开始外层if-else语句 # 开始内层if-elif-else嵌套语句 # 结束内层if-elif-else嵌套语句 # 结束外层if-else语句 【例332】判断用户输入的整数是否能够被2或者3整除。 1 2 3 4 5 6 7 8 9 10 11 12 #E0332.py num = 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嵌套】 # if语句块1开始,%为模运算 # 内层if嵌套语句块2开始 # if语句块2部分 # 内层if嵌套语句块2结束 # if语句块1部分 # 内层if嵌套语句块3开始 # if语句块3部分 # if语句块3,语句块1结束 >>> 输入一个数字:55 输入的数字不能整除2和3 # 程序运行结果 程序第3~12行为if语句块1; 程序第4~7行为if语句块2; 程序第9~12行为if语句块3。 【例333】一元二次方程44x2+123x-54=0求根(方法3,比较例318、例329)。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #E0333.py import 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("x1=", x1, "\t", "x2=", x2) # 【解一元二次方程C】 # 导入标准模块-数学计算 # 将输入信息转换为浮点数 # 如果判别式不等于0 # 计算方程判别式 # 如果判别式小于0 # 如果判别式等于0 # 计算方程的唯一根 # 计算方程判别式 # 计算方程的根1 # 计算方程的根2 # 参数"\t"=制表符(空4格) >>> 请输入二次项系数a:44 请输入一次项系数b:123 请输入常数项系数c:-54 x1= 0.3857845035720447x2= -3.18123904902659 # 程序输出 3.3循 环 语 句 3.3.1for计数循环 1. for循环基本结构 循环是为了实现程序中部分语句的重复执行。Python有两种循环结构,for计数循环(用于循环次数确定的情况)和while条件循环(用于循环次数不确定的情况)。 for循环可以对序列中每个元素逐个访问(称为遍历)。序列可以是列表、字符串、元组等,也可以用range()函数生成顺序整数序列(整数等差数列)。 for循环语法格式1: 1 2 for临时变量 in 序列: 循环语句块 #将序列中每个元素逐个代入临时变量 【例334】简单字符串for循环语句设计。 1 2 3names = ['唐僧', '孙悟空', '猪八戒', '沙和尚'] for n in names: print(n)# 定义列表(序列) # 将names中的元素逐个顺序代入临时变量n # 执行循环语句块 >>>唐僧 孙悟空 猪八戒 沙和尚 # 注:输出为竖行 【例335】用for循环语句设计一个打字机输出效果。 1 2 3 4 5 6 7 8 9 10 #E0335.py import 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.2s(用暂停形成打字机效果) # 输出字符串 >>> pain past is pleasure….(输出略) # 程序运行结果 2. for循环执行过程 步骤1: 循环开始时,for语句内部计数器自动设置索引号为0,并读取序列(如列表等)中0号元素,如果序列为空,则循环自动结束并退出循环; 步骤2: 如果序列不为空,则for语句读取索引号指定元素,并将它复制到临时变量; 步骤3: 执行循环中语句块,循环语句块执行完后,一次循环执行完毕; 步骤4: for语句内部计数器将索引号自动加1,继续访问下一个元素; 步骤5: for语句自动判断,如果序列中存在下一个元素,则重复执行步骤2~5; 步骤6: 如果序列中已经没有元素了,for语句会自动退出当前循环语句。 【例336】用循环结构计算1~10的整数和。 1 2 3 4 sum = 0 for x in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]: sum = sum + x print('1+2+3+…+10=', sum) # 变量初始化,sum变量用于存放累加值 # 按列表进行循环计算 # 累加计算 >>>1+2+3+…+10= 55 # 程序运行结果 3. for循环扩展结构 循环程序经常用range()函数生成顺序整数序列(称为列表生成式),语法如下。 range(起始索引号,终止索引号,步长) #整数序列生成语法 参数“起始索引号”默认从0开始,如range(5)等价于range(0, 5),共5个元素。 参数“终止索引号”即停止数,但不包括停止数本身,如range(0, 5)共5个元素。 参数“步长”即每个整数的增量,默认为1,如: range(0, 5)等价于range(0, 5, 1)。 range()函数返回一个[顺序整数列表]。 for循环语法格式2: 1 2 for临时变量 in range(): 循环语句块 #将range()函数生成的整数序列顺序代入临时变量 【例337】一个球从100m高度自由落下,每次落地后反弹回原高度的一半再落下。球在第10次落地时的反弹高度是多少?球一共经过的路程是多少? 1 2 3 4 5 6 7 8 #E0337.py high = 100 total = 0 for i in range(10): high /= 2 total += high print('球第', i+1, '次反弹高度:', high) print('球总共经过的路程为[米]:', total) # 【球的反弹】 # 高度赋值 # 总共经过的路程 # 计数循环,range(10)=生成0~10的整数 # 计算反弹高度(反弹高度每次除2) # 计算总路程 # 注意,索引号i从0开始,因此需要加1 >>>球第1次反弹高度: 50.0…(输出略)# 程序运行结果 4. 列表推导式 列表推导是构建列表的快捷方式,它可读性更好,而且效率更高。如果想简单、高效地生成满足特定需要的列表,可以使用列表推导式。 1 2 表达式 for 临时变量 in 列表 表达式 for 临时变量 in 列表 if 条件 # 语法格式1 # 语法格式2 【例338】利用列表推导生成一个等差数列列表。 1 2 3 >>>ls = [1, 2, 3, 4, 5, 6, 7, 8] >>>ls = [i*i for i in ls] >>>ls [1, 4, 9, 16, 25, 36, 49, 64] # 定义列表ls # 用ls列表中各元素的平方生成一个新列表 # 输出列表ls 【例339】假设有一个学生成绩列表,请选出分数在80~90分的成绩。 1 2 >>>scores = [45, 82, 75, 88, 91, 68, 90, 70] >>>print('成绩过滤:', [s for s in scores if s >=80 and s < 90]) 成绩过滤: [82, 88]# 定义成绩列表 # 打印列表推导式 程序第2行,列表推导式语句看上去很复杂,并且难以理解。如图31所示,对复杂语句可以从右到左,按子句逐个分解,这样理解起来就容易多了。 图31列表推导式结构示意图 3.3.2while条件循环 1. while循环结构 while循环在运行前先判断条件表达式,如果满足条件再循环。while语法如下。 1 2while 条件表达式: 循环语句块# 如果条件表达式=True,则执行循环语句块 # 如果条件表达式=False,则结束循环语句 【例340】用while循环计算1到100的累加和。 1 2 3 4 5 6 7n = 100 sum = 0 counter = 1 while counter <= n: sum = sum + counter counter += 1 print('1到%d之和=%d' %(n, sum)) # 定义循环终止条件 # sum存放累加和,初始化变量 # 定义计数器变量,记录循环次数,并作为累加增量 # 循环判断,如果counter<=n为True,则执行下面语句 # 累加和(sum值+counter值后,再存入sum单元) # 循环计数(ounter<=n为False时结束循环) # 循环外语句,打印累加和 >>>1到100之和=5050 # 程序运行结果 2. 无限循环 如果循环语句的条件表达式永远不为False,就会导致出现无限循环(也称为死循环)的情况。无限循环在网络服务端程序设计中非常有用,但是在大部分时候,在程序设计中应当尽量避免。出现无限循环可以通过按Ctrl+C组合键,强制退出循环; 或者通过关闭Python调试窗口强制退出循环。 【例341】无限循环示例。 1 2 3 4while True: num = int(input('请输入一个整数:')) print('你输入的数字是:', num) print('按[Ctrl+C]键强制退出循环') # 循环条件表达式永远=True >>>…(输出略)# 程序运行结果 3. while循环程序案例 【例342】输出简单正三角形。【例343】输出简单倒三角形。 1 2 3 4i = 1# 变量初始化 while i <= 5:# 循环终止条件 print("*" * i)# 打印*号 i += 1# 自加运算 >>> * ** *** **** ***** 1 2 3 4i = 5# 变量初始化 while i >= 0: # 循环终止条件 print("*" * i) # 打印*号 i -= 1 # 自减运算 >>> ***** **** *** ** * 3.3.3循环中止 1. 用continue语句跳过循环块中剩余语句 continue语句用来跳过当前循环块中的剩余语句,然后继续进行下一轮循环。 【例344】在循环语句中,用continue语句跳过某个字符的输出。 1 2 3 4 for s in '人间四月芳菲尽': if s == '芳': continue print(s) # 依次循环取出字符串列表中的字符 # 如果字符为'芳' # 则跳过这个字符,返回到循环开始处重新循环 >>>人间四月菲尽 # 注,输出为竖行 2. 用break语句强制跳出循环 break语句可以强制跳出for和while循环体。break语句一般与if语句配合使用,在特定条件满足时,达到跳出循环体的目的。 【例345】在循环语句中,用break语句强制跳出循环。 1 2 3 4for s in '人间四月芳菲尽': if s == '芳': break print(s) # 依次循环取出字符串列表中的字符 # 如果字符="芳" # 则强制退出循环(比较与例3-44的区别) >>>人间四月 # 注:输出为竖行 【例346】在“石头剪刀布”游戏程序中强制跳出循环。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #E0346.py import random guess_list = ['石头', '剪刀', '布'] win_combination = [['布', '石头'], ['石头', '剪刀'], ['剪刀', '布']] while True: computer = random.choice(guess_list) people = input('请输入【石头,剪刀,布】=').strip() if people not in guess_list: people = input('请重新输入【石头,剪刀,布】=').strip() continue if computer == people: print('平手,再玩一次!') elif [computer, people] in win_combination: print('电脑获胜!') else: print('你获胜!') break # 【石头-剪刀-布】 # 导入标准模块-随机数 # 定义字符串列表 # 定义输赢标准 # 无限循环(死循环) # 生成随机数 # 用户输入 # 判断输赢方 # 重新输入 # 回到循环起始处 # 判断输赢 # 判断输赢 # 否则,人获胜 # 人获胜则退出循环 >>> 请输入【石头,剪刀,布】=石头 平手,再玩一次! 请输入【石头,剪刀,布】=布 你获胜!!! # 程序运行结果 3.3.4循环嵌套 循环嵌套就是一条循环语句里面还有另外一条循环语句,当两个以上的循环语句相互嵌套时,位于外层的循环结构简称为外循环,位于内层的循环结构简称为内循环。循环嵌套会导致代码阅读性非常差,因此要避免出现三个以上的循环嵌套。 输出一个多行字符串需要两个嵌套在一起的循环。第2个循环(内循环)在第1个循环(外循环)内部。循环嵌套是每一次外层循环时,都要进行一遍内层循环。 【例347】利用循环嵌套打印乘法口诀表。 1 2 3 4 5 #E0347.py for i in range(1, 10): for j in range(1, i+1): print('{}×{}={}\t'.format(j, i, i*j), end='') print() # 【打印乘法口诀表】 # 外循环打印行(最大9行) # 内循环打印一行中的列(最大9列) # 按格式打印输出每一个乘法口诀 # 换行 >>> # 程序运行结果 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 程序第2行,for i in range(1, 10)为外循环,它控制行输出,一共打印9行。 程序第3行,for j in range(1, i+1)为内循环,它控制一行中每个表达式(如1×1=1)的输出,由于循环变量i=10,因此每行最多输出9个乘法口诀。 程序第4行,print('{}×{}={}\t'.format(j, i, i*j), end='')为控制打印格式; j值对应第1个{},i值对应第2个{},i*j的值对应第3个{}; end=''为不换行打印。 程序第5行,print()语句属于外循环,因此语句缩进与第3行for语句对齐,外循环每次循环中,它都会执行一次。print()语句没有写任何东西,它只起到换行作用。 【例348】判断1~100有多少个素数,并输出所有素数。 判断素数的方法: 公元前250年,古希腊数学家厄拉多赛(Eratosthenes)提出了一个构造出不超过n的素数算法。它基于一个简单的性质: 对正整数n,如果用2~n的所有整数去除,均无法整除,则n为素数。 1 2 3 4 5 6 7 8 #E0348.py import math for n in range(1, 100): for j in range(2, round(math.sqrt(n))+1): if n%j == 0: break else: print('素数', n) # 【求素数】 # 导入标准模块-数学 # 外循环,n=1~100的顺序整数 # 内循环,i为2至sqrt(n)之间的整数 # 求余运算:n%j=0是合数(能整除) # 退出内循环 # 否则 # n%j≠0是素数 >>>素数1 素数2 素数3…(输出略) # 程序运行结果(注,输出为竖行) 程序第4行,n为外循环顺序整数,j为内循环2至sqrt(n)之间的整数; math.sqrt(n)为求n开方值; round()为取整数; range()为创建顺序整数。语句为循环筛选素数。 程序第5行,n和j求余为0,则n不是素数; 如果n和j求余不为0,则n为素数。 3.3.5案例: 猜数字游戏 猜数字大小是一种古老的密码破译类小游戏,一般由两个人玩,也可以由一个人与计算机玩。下面用Python设计这个经典小游戏。在游戏中,应用了以下程序设计知识: 变量赋值、函数参数传递、随机数生成、条件判断、循环嵌套、强制退出循环、计数、用户数据输入、错误处理等。 【例349】“猜年龄”游戏程序如下所示。 1 2 3 4 5 6 7 8 #E0349.py import random print('=== 猜猜mm芳龄几何 ===') def judge(x): while not x.isdigit(): print('拜托,不要用脚敲键盘!还有'+count+'次') x = input('敲黑板!好好输[1-60]:') # 【游戏-猜年龄】 # 导入标准模块-随机数 # 定义数据类型错误处理函数 # 输入是否为非数值类型 # 用户重新输入数据 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 num = int(x) if (num<0) or (num>60): print('请不要乱敲键盘哦,还有'+count+'次') x = input('敲黑板!好好输[1-60]:') judge(x) return num T = 'Y' while (T == 'Y') or (T == 'y'): num = random.randint(1, 60) for i in range(0, 7): if i != 6: count = str(6-i) print('你有6次机会,还剩'+count+'次') x = input('猜猜我的年龄多大[1-60]:') x = judge(x) if x == num: print('^_^ 猜对了!我们做朋友吧') break else: if x > num: print('帅哥,我有那么老吗?') else: print('小弟,比你稍稍大点!') else: print('【游戏结束】') break T = input('继续游戏输入y,回车键退出:') # 对输入数据取整 # 检查数据是否超出范围 # 调用自身,处理输入错误 # 则返回用户输入数据 # 初始化循环条件 # 外循环,判断是否再玩游戏 # randint()生成1~60的随机整数 # 内循环,range()生成顺序整数 # 判断猜的次数 # 循环计数-1 # 用户输入数据 # 调用函数检测输入是否错误 # 如果猜数=随机数 # 强制退出循环 # 猜数>随机数 # 否则,猜数<随机数 # 否则,猜的次数等于6次 # 强制退出循环 # 检测是否退出外循环while >>> …(输出略) # 程序运行结果 3.3.6案例: 走迷宫游戏 【例350】利用循环语句和多条件判断语句,设计一个走迷宫游戏。 (1) 迷宫设计。走迷宫程序首先要确定迷宫的宽和高、迷宫矩阵的形式以及迷宫的入口和出口。迷宫矩阵中的每一个元素可以设置为0(输出为空格)或1(输出为■),0表示道路,可走,1表示墙,走不通。我们用坐标(x,y)表示走迷宫的精灵(输出为☆)。程序首先读入迷宫矩阵数据,然后显示迷宫矩阵。 (2) 输入判断。用循环语句+多条件判断语句检测玩家的键盘输入(w、s、a、d)。玩家在键盘输入中,可能会出现输入错误的情况,程序需要进行错误处理。 (3) 碰撞检测。通过玩家输入的字符,计算精灵移动的坐标。如果精灵坐标的上、下、左、右是1(墙),则跳出循环,结束游戏; 如果上、下、左、右不是1,则精灵按输入方向移动。 (4) 胜利判断。精灵移动到出口位置(endx,endy)时,强制跳出循环,玩家胜利。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #E0350.py # 【定义迷宫路径】 my_map = [ [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 1, 1], [1, 2, 1, 1, 1, 1, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1, 1, 1, 1], [1, 0, 1, 1, 1, 0, 0, 0, 0, 0], [1, 0, 1, 1, 1, 1, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1, 0, 1, 1], [1, 0, 1, 1, 1, 1, 1, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1], ] # 【精灵起点与迷宫出口】 x, y = 1, 2 endx, endy = 9, 4 # 【打印迷宫】 def print_map(): for m in my_map: for n in m: if n == 1: print('■', end='') elif(n == 0): print(' ', end='') else: print('☆', end='') print('') print_map() # 【游戏主循环】 while True: print('☆表示精灵当前位置') # 【检测玩家输入】 key = input('请输入指令【w上, s下, a左,d右】:') # 【碰撞检测】 if key == 'a': x = x-1 if my_map[y][x] == 1: print('囧,碰壁了,游戏结束!') break else: my_map[y][x], my_map[y][x+1] =\ my_map[y][x+1], my_map[y][x] print_map() elif key == 's': y = y + 1 if my_map[y][x] == 1: print('囧,碰壁了,游戏结束!') break else: my_map[y][x], my_map[y-1][x] =\ my_map[y-1][x], my_map[y][x] print_map() elif key == 'd': x = x + 1 # 【游戏-走迷宫】 # 利用列表嵌套定义迷宫地图 # 定义一个10×10的二维列表 # 1表示墙,0表示路,2表示精灵☆位置 # 精灵起始x,y坐标 # 迷宫出口x,y坐标 # 定义迷宫打印函数 # 循环输出全部行 # 循环输出一行中列的字符 # 如果地图数据=1 # 输出■(墙) # 如果地图数据=0 # 输出空格(路)end=""不换行 # 否则,输出精灵☆ # 打印精灵,并换行 # 打印迷宫地图 # 游戏主循环(无限循环) # 提示信息 # 等待玩家输入 # a为玩家输入 # 计算x坐标值 # 碰撞检测,判断my_map[y][x] # (第y列第x行)的值是否为1 # 强制退出循环,结束游戏 # 否则 # 交换坐标值(A,B = B,A) # \为续行符 # print_map()打印迷宫地图 # s为玩家输入 # 计算y坐标值 # x,y=1时表示碰壁 # 强制退出循环 # 计算迷宫坐标值 # 打印迷宫地图 # d为玩家输入 # 计算x坐标值 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 if my_map[y][x] == 1: print('囧,碰壁了,游戏结束!') break else: my_map[y][x], my_map[y][x-1] =\ my_map[y][x - 1], my_map[y][x] print_map() if my_map[y][x] == my_map[endy][endx]: print('恭喜你,过关了!^_^') break elif key == 'w': y = y - 1 if my_map[y][x] == 1: print('囧,碰壁了,游戏结束!') break else: my_map[y][x], my_map[y+1][x] =\ my_map[y+1][x], my_map[y][x] print_map() # 【检测玩家输入错误】 else: print('输入指令错误,请重新输入指令:') continue # x,y=1时表示碰壁 # 强制退出循环 # 计算迷宫坐标 # 打印迷宫地图 # 强制退出循环 # w为玩家输入 # 计算y坐标值 # x,y=1时表示碰壁 # 强制退出循环 # 计算迷宫坐标 # 打印迷宫地图 # 等待玩家输入 # 回到循环头,继续循环 >>> ■■■■■■■■■■ ■■■ ■☆■■■■■■■ ■■■■■■■■■ ■■■■ ■■■■■■■■ ■■■■■■■■ ■■■■■■■■ ■■■ ■■■■■■■■■■ ☆表示精灵当前位置 请输入指令【w上, s下, a左,d右】: # 程序运行结果 习题3 31模块导入的功能是什么? 32模块导入有哪些原则? 33说明语句import matplotlib.pyplot as plt各部分的功能。 34赋值语句应当注意哪些问题? 35例318、例329、例333都是对一元二次方程求根,它们有什么不同? 36编程: 输入三个整数,请把这三个数按由小到大的排序输出。 37编程: 学习成绩大于或等于85分用“优”表示; 75~84分用“良”表示; 60~74分用“及格”表示; 60分以下用“不及格”表示。用键盘输入成绩,显示成绩等级。 38编程: 兔子问题(斐波那契数列)。有一对兔子,从出生后第3个月起,每个月都生一对兔子,小兔子长到第3个月后,每个月又生一对兔子。假如兔子都不死,问每个月兔子总数为多少? 39编程: 打印100~1000的所有“水仙花数”。“水仙花数”是指一个三位数,各位数字的立方和等于该数本身。例如,153是一个“水仙花数”,因为153=13+53+33。 310编程: 输入一行字符,统计出其中字母、空格、数字和其他字符的个数。