4.程序的控制结构
4.1 程序的分支结构
单分支结构
-
单分支结构:根据判断条件结果而选择不同向前路径的运行方式
if<条件>:<语句块>语句块>条件>
二分支结构
-
二分支结构:根据判断条件结果而选择不同的向前路径的运行方式
if<条件>:<语句块1>语句块1>条件>
else:<语句块2>语句块2>
-
紧凑形式:适用于简单表达式的二分支结构
<表达式1> if <条件> else <表达式2> 表达式2>条件>表达式1>
guess=eval(input())
if guess==99:
print("猜对了")
else:
print("猜错了")
guess=eval(input())
print("猜{}了".format("对" if guess=99 else "错"))
#注意这种紧凑形式是有返回值的表达式而不是一段语句
#也有类似这样的紧凑形式:n_ = n_+1 if n_ < n else n_
#但是请注意把n_+1 if n_ < n else n_当作整体理解
多分支结构
-
多分支结构:根据多个条件来选择不同语句块运行的一种分支机构
if<条件>:<语句块>语句块>条件>
elif<条件>:<语句块>语句块>条件>
elif<条件>:<语句块>语句块>条件>
…
else:<语句块>语句块>
条件判断及组合
- 条件判断
- 操作符
- < 小于
- <= 小于等于
- >= 大于等于
- > 大于
- == 等于
- != 不等于
- 用于条件组合的保留字
- x and y:xy两个条件的逻辑与
- x or y:xy两个条件的逻辑或
- not x:x的逻辑非
- 操作符
程序的异常处理
举例
num=eval(input("请输入一个整数:"))
print(num**2)
如果用户输入的是字符串abc,程序会异常退出,并给出异常信息
Traceback(most recent call last):
File "t.py", line 1,in <module>
num=eval(input("请输入一个整数:"))
File "<string>", line 1,in <module>
NameError: name 'abc' is not defined
其中“line 1”表示异常发生的代码行数
“NameError”是异常类型#重要
“name 'abc' is not defined”是异常内容提示,输入的'abc'经过eval处理,去掉引号变成了变量abc,而变量abc没有被定义
-
异常处理的基本使用
try:<语句块1>语句块1>
except:<语句块2>语句块2>
要执行的程序放语句块1,如果出现异常则执行语句块2,不出现异常则跳过语句块2
也有
try:<语句块1>语句块1>
except<异常类型>:<语句块2>语句块2>异常类型>
仅当出现的异常类型为except后指示的异常时执行语句块2
try:
num=eval(input("请输入一个整数:"))
print(num**2)
except:
print("输入不是整数")
或者
try:
num=eval(input("请输入一个整数:"))
print(num**2)
except NameError:
print("输入不是整数")
-
异常处理的高级使用方法
try:<语句块1>语句块1>
except:<语句块2>语句块2>
else:<语句块3>语句块3>
finally:<语句块4> 当执行语句块1不发生异常,执行语句块3,如果发生异常,执行语句块2,但最后无论发不发生异常都执行语句块4语句块4>
4.2 实例5:身体质量指数BMI
问题分析
-
BMI:对身体质量的刻画(Body Mass Index)
-
BMI=体重(kg)/身高(m)的平方
-
国际:世界卫生组织;国内:国家卫生健康委员会
分类:
国际BMI 国内BMI
偏瘦 <18.5 <18.5
正常 18.5~25 18.5~24
偏胖 25~30 24~28
肥胖 >=30 >=28
-
问题需求
- 输入:给定体重和升高值
- 输出:BMI指标分类信息(国际和国内)
实例讲解
- 思路方法
- 难点在于同时输出国际和国内对应的分类
- 思路1:分别计算并给出国际和国内BMI分类
- 思路2:混合计算并给出国际和国内BMI分类
#CalBMIv1.py
height,weight=eval(input("请输入身高(米)和体重\(公斤)[逗号隔开]:"))
bmi=weight/pow(height,2)
print("BMI 数值为:{:.2f}".format(bmi))
who=""
if bmi<18.5:
who="偏瘦"
elif 18.5<=bmi<25:
who="正常"
elif 25<=bmi<30:
who="偏胖"
else:
who="肥胖"
print("BMI 指标为:国际'{0}'".format(who))
#CalBMIv2.py
height,weight=eval(input("请输入身高(米)和体重\(公斤)[逗号隔开]:"))
bmi=weight/pow(height,2)
print("BMI 数值为:{:.2f}".format(bmi))
nat=""
if bmi<18.5:
nat="偏瘦"
elif 18.5<=bmi<24:
nat="正常"
elif 24<=bmi<28:
nat="偏胖"
else:
nat="肥胖"
print("BMI 指标为:国内'{0}'".format(nat))
#CalBMIv3.py
height,weight=eval(input("请输入身高(米)和体重\(公斤)[逗号隔开]:"))
bmi=weight/pow(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}',国内'{1}'".format(who,nat))
举一反三
- 关注多分支条件的组合
- 多分支条件之间的覆盖是重要问题
- 避免程序可运行,但不正确的情况,注意多分支
- 分支结构是程序的重要框架,读程序优先看分支,再看细节
4.3 程序的循环结构
遍历循环
-
遍历循环:遍历某个结构形成的循环运行方式
-
for <循环变量> in <遍历结构>:遍历结构>循环变量>
<语句块>语句块>
-
从遍历结构中逐一提取元素,放在循环变量中
-
由保留字for和in组成,完整遍历所有元素后结束
-
每次循环,所获得元素放入循环变量,并执行一次语句块(在语句块中可以使用循环变量)
-
-
遍历循环的运用
-
计数循环(N次)
for i in range(N):
<语句块>语句块>
遍历由range()函数产生的数字序列,产生循环
-
计数循环(特定次)
for i in range(M,N,K):
<语句块>语句块>
如
>>>for i in range(1,6):
print(i)
1
2
3
4
5
>>>for i in range(1,6,2)
print(“Hello:”,i)
Hello:1
Hello:3
Hello:5
-
字符串遍历循环
for c in s:
<语句块>语句块>
s是字符串,遍历字符串中每个字符c,产生循环
如
>>>for c in “Python123”
print(c,end=”,”)
P,y,t,h,o,n,1,2,3,
-
列表遍历循环
for item in ls:
<语句块>语句块>
ls是一个列表,遍历其中每个元素,产生循环
如
>>>for item in [123,”PY”,456]:
print(item,end=”,”)
123,PY,456,
-
文件遍历循环
for line in fi:
<语句块>语句块>
fi是一个文件标识符,遍历其每行,产生循环
- 文件标识符:对外部一个文件用Python的函数打开,如果该文件是以字符形式打开,那么它就会表现为文件的标识的名字。即用一个变量标识系统中的一个文件,这个变量就是文件标识符。
-
元组,字典类型遍历循环。。。
-
掌握概念:遍历结构是一个由多个元素构成的数据类型,就可以用for in的方式遍历它,遍历次数即该遍历结构的元素个数
-
无限循环
-
无限循环:由条件控制的循环运行方式
while <条件>:条件>
<语句块>语句块>
反复执行语句块,直到条件不满足时退出
如
>>>a=3
>>>while a>0:
a=a-1
print(a)
2
1
0
>>>a=3
>>>while a>0:
a=a+1
print(a)
4
5
…(一直输出,可按CTRL+C退出执行)
循环控制保留字
- break:跳出并结束当前整个循环,执行循环后的语句
- continue:结束当次循环,继续执行后续次数循环
- 两者都可与for/while搭配
如
>>>for c in “PYTHON”:
if c==”T”:
continue
print(c,end=””)
PYHON
>>>for c in “PYTHON”:
if c==”T”:
break
print(c,end=””)
PY
break退出当前整个循环啥意思啊?如下
>>>s=”PYTHON”
>>>while s!=””
for c in s:
print(c,end=””)
s=s[:-1]
PYTHONPYTHOPYTHPYTPYP
>>>s=”PYTHON”
>>>while s!=””
for c in s:
if c == “T”:
break
print(c,end=””)
s=s[:-1]
PYPYPYPYPYP
即break退出的是当前整个即for循环,而不会退出while循环,一个break跳出一层循环(最内层)
循环的高级用法
-
循环与else
for <循环变量> in <遍历结构>:遍历结构>循环变量>
<语句块1>语句块1>
else:
<语句块2>语句块2>
while <条件>:条件>
<语句块1>语句块1>
else:
<语句块2>语句块2>
-
当循环没有被break语句退出时,执行else语句块
- else语句块可看作”正常“完成循环的奖励
- 这里的else用法与异常处理中else用法相似
如
>>>for c in “PYTHON”:
if c==”T”:
continue
print(c,end=””)
else:
print(“正常退出”)
PYHON正常退出
>>>for c in “PYTHON”:
if c==”T”:
break
print(c,end=””)
else:
print(“正常退出”)
PY
-
4.4 模块3:random库的使用
random库基本介绍
-
random库概述:random库是使用随机数的Python标准库(随Python解释器安装)
小tip:计算机无法真正产生随机数,它所谓的随机数是用一种特定方法计算出来的看似随机的特定数
- 伪随机数:采用梅森旋转算法生成的(伪)随机序列中元素
- random库主要用于生成随机数
- 使用:import random
-
random库的函数
- random库包括两类函数,常用的有8个
- 基本随机数函数:seed(),random()
- 扩展随机数函数:randint(),getrandbits(),uniform(),randrange(),choice(),shuffle()
基本随机数函数
-
随机数种子
如给定随机数种子10,根据梅森旋转算法,整出随机序列,其中的每个数就“叫”随机数
-
seed(a=None)
初始化给定的随机种子,默认为当前系统时间
>>>random.seed(10)#产生种子10对应的序列
当然,在使用随机数的时候可不用这个函数,直接用random()函数,这时它将使用当前操作系统的默认系统时间为种子
-
random()
生成一个[0.0,1.0)之间的随机小数
>>>random.random()
0.5714025946899135
产生的随机小数与种子有关,如用了种子10,那么产生的第一个随机小数一定是上面的0.57
如
>>>import random
>>>random.seed(10)
>>>random.random()
0.5714025946899135
>>>random.random()
0.4288890546751146
…
给定随机数种子可以复现程序的运算过程,而不会让程序因为采用系统时间为种子造成每次程序的运算结果不同
如
>>>import random
>>>random.seed(10)
>>>random.random()
0.5714025946899135
>>>random.seed(10)
>>>random.random()
0.5714025946899135
扩展随机数函数
-
randint(a,b)
生成一个[a,b]之间的整数
>>>random.randint(10,100)
64
-
randrange(m,n[,k])
生成一个[m,n)之间以k为步长的随机整数
>>>random.randrange(10,100,10)
80
-
getrandbits(k)
生成一个k比特长的随机整数
>>>random.getrandbits(16)
37885
-
uniform(a,b)
生成一个[a,b]之间的随机小数
>>>random.uniform(10,100)
13.096321648808136
-
choice(seq)
从序列seq中随机选择一个元素
>>>random.choice([1,2,3,4,5,6,7,8,9])
8
-
shuffle(seq)
将序列seq中元素随机排列,返回打乱后的序列
>>>s=[1,2,3,4,5,6,7,8,9];random.shuffle(s);print(s)
[3,5,8,9,6,1,2,7,4]
-
随机数函数的使用
- 需要掌握的能力
- 能够利用随机数种子产生“确定”伪随机数
- 能够产生随机整数
- 能够对序列类型进行随机操作
- 需要掌握的能力
4.5 实例6:圆周率的计算
“圆周率的计算”问题分析
-
圆周率的近似计算公式
$\pi=\sum_{k=0}^{\infty}[\frac{1}{16^{k}}(\frac{4}{8k+1}-\frac{2}{8k+4}-\frac{1}{8k+5}-\frac{1}{8k+6})]$
-
工程上:蒙特卡罗方法
圆周率相当于单位圆的面积去除以边长为2的正方形的面积
那么对于“边长为2的正方形框住单位圆”的图形,对它进行“撒点”,每个点随机出现在图形中,如果给出点的数量足够庞大,就可以通过正方形的面积、撒在圆和正方形中点的数量的比值计算出圆的面积
“圆周率的计算”实例讲解
- 圆周率的近似计算公式
#CalPiV1.py
pi=0
N=100
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("圆周率值是:{}".format(pi))
用\换行后的代码和写在一行是一致的,可增加可读性
- 蒙特卡罗方法
#CalPiV2.py
from random import random
from time import perf_counter
DARTS=1000*1000
hits=0.0
start=perf_counter()
for i in range(1,DARTS+1):
x,y=random(),random()
dist=pow(x**2+y**2,0.5)
if dist<=1.0:
hits=hits+1
pi=4*(hits/DARTS)
print("圆周率值是:{}".format(pi))
print("运行时间是:{:.5f}s".format(perf_counter()-start))
“圆周率的计算”举一反三
-
理解方法思维
-
数学思维:找到公式,利用公式求解
-
计算思维:抽象一种过程,用计算机自动化求解
-
谁更准确?
-
存在精确公式时数学思维当然准确,但不是每个问题都有精确公式
- 当对精度要求不大时可以用数学思维(近似公式),要求大时可采用计算思维(更多次随机,结果更精确)
- 四色定理:并不能用数学公式解决,最终是由计算机用计算思维解决的
-
-
- 程序运行时间分析
- 使用time库的计时方法获得程序运行时间
- 改变撒点数量,理解程序运行时间的分布
- 一般来说,一个程序的主要运行时间应该都花在循环上
- 初步掌握简单的程序性能分析方法
- 计算问题的扩展
- 不求解圆周率,而是某个特定图形面积
- 在工程计算中寻找蒙特卡罗方法的应用场景
练习
-
实例5:身体质量指数BMI
描述
这是”实例”题,与课上讲解实例相同,请作答检验学习效果。
BMI :Body Mass Index 国际上常用的衡量人体肥胖和健康程度重要标准,主要用于统计分析
定义:BMI = 体重 (kg) /身高2(m2)
获取用户输入的体重和身高值,计算并给出国际和国内的 BMI 分类
要求如下:
(1) 混合计算并给出国际和国内的 BMI 分类;
(2) 使用input()获得测试用例输入时,不要增加提示字符串。
## 输入输出示例
输入 | 输出 | |
---|---|---|
示例1 | 1.68,41 |
BMI数值为:14.53 BMI指标为:国际'偏瘦',国内'偏瘦' |
示例2 | 1.72,80 |
BMI数值为:27.04 BMI指标为:国际'偏胖',国内'偏胖' |
height,weight=eval(input())
bmi=weight/pow(height,2)
print("BMI数值为:{:.2f}".format(bmi))
if bmi<18.5:
print("BMI指标为:国际'偏瘦',国内'偏瘦'")
elif 18.5<=bmi<24:
print("BMI指标为:国际'正常',国内'正常'")
elif 24<=bmi<25:
print("BMI指标为:国际'正常',国内'偏胖'")
elif 25<=bmi<28:
print("BMI指标为:国际'偏胖',国内'偏胖'")
elif 28<=bmi<30:
print("BMI指标为:国际'偏胖',国内'肥胖'")
else:
print("BMI指标为:国际'肥胖',国内'肥胖'")
-
实例6:圆周率的计算
描述
这是”实例”题,与课上讲解实例相同,请作答检验学习效果。
求解圆周率可以采用蒙特卡罗方法,在一个正方形中撒点,根据在1/4圆内点的数量占总撒点数的比例计算圆周率值。
请以123作为随机数种子,获得用户输入的撒点数量,编写程序输出圆周率的值,保留小数点后6位。
输入输出示例
输入 输出 示例 1 1024
3.218750
import random
random.seed(123)
n=eval(input())
hits=0
for i in range(1,n+1):
x,y=random.random(),random.random()
dist=(x**2+y**2)**0.5
if dist<=1.0:
hits=hits+1
pi=4*(hits/n)
print("{:.6f}".format(pi))
---
from random import random, seed
DARTS = eval(input())
seed(123)
hits = 0.0
for i in range(DARTS):
x, y = random(), random()
dist = pow(x ** 2 + y ** 2, 0.5)
if dist <= 1.0:
hits = hits + 1
pi = 4 * (hits/DARTS)
print("{:.6f}".format(pi))
-
整数的加减和
描述
编写程序计算如下数列的值:
1-2+3-4…966
其中,所有数字为整数,从1开始递增,奇数为正,偶数为负
输入格式
该题目没有输入。
输入输出示例
输入 输出 示例 1 无
111(仅表示输出样式,不是输出结果)
ans=0
for i in range(1,967):
if i%2==1:
ans=ans+i
else:
ans=ans-i
print(ans)
-
三位水仙花数
描述
“水仙花数”是指一个三位整数,其各位数字的3次方和等于该数本身。
例如:ABC是一个”3位水仙花数”,则:A的3次方+B的3次方+C的3次方 = ABC。
请按照从小到大的顺序输出所有的3位水仙花数,请用”逗号”分隔输出结果。
输入输出示例
输出仅表示格式,不表示对错。
输入 输出 示例 1 无输入
111,222
b=0
for i in range(100,1000):
if (((i//100)**3)+(((i%100)//10)**3)+((i%10)**3))==i:
if b==0:
print(i,end="")
b=1
else:
print(",{}".format(i),end="")
---
s = ""
for i in range(100, 1000):
t = str(i)
if pow(eval(t[0]),3) + pow(eval(t[1]),3) + pow(eval(t[2]),3) == i :
s += "{},".format(i)
print(s[:-1])
#这里采用了s[:-1]方式不输出最后一个逗号。也可以把所有结果放到一个列表中,采用字符串的.join()方法输出结果。
-
用户登录的三次机会
描述
给用户三次输入用户名和密码的机会,要求如下:
1)如输入第一行输入用户名为‘Kate’,第二行输入密码为‘666666’,输出‘登录成功!’,退出程序;
2)当一共有3次输入用户名或密码不正确输出“3次用户名或者密码均有误!退出程序。”。
输入输出示例
输入 输出 示例 1 Kate 666666
登录成功!
kate 123 alice 456 john 111111
3次用户名或者密码均有误!退出程序。
standard_name='Kate'
standard_code='666666'
for i in range(3):
s1=input()
s2=input()
#读字符串不可以s1,s2=input()
if (s1==standard_name) and (s2==standard_code):
print("登录成功!")
break
elif i==2:
print("3次用户名或者密码均有误!退出程序。")
---
count = 0
while count < 3:
name = input()
password = input()
if name == 'Kate'and password == '666666':
print("登录成功!")
break
else:
count += 1
if count == 3:
print("3次用户名或者密码均有误!退出程序。")
测验
单项选择题
-
for var in ___: print(var)
哪个选项不符合上述程序空白处的语法要求?
A. (1,2,3)
B. “Hello”
C. {1;2;3;4;5}
D. range(0,10)
C
for .. in .. 中 in 的后面需要是一个迭代类型(组合类型),{1;2;3;4;5}不是Python的有效数据类型。
-
for i in range(0,2): print(i)
哪个选项是以上程序的输出结果?
A. 0 1
B. 1
C. 1 2
D. 0 1 2
A
range(0, 2)输出两个值:0和1。
-
k=10000 while k>1: print(k) k=k/2
哪个选项给出了上述程序的输出次数?
A. 1000
B. 15
C. 13
D. 14
D
请跟随程序计算或在IDLE中运行程序获得结果。
-
哪个选项是程序的三种基本结构?
A. 顺序结构,循环结构,分支结构
B. 顺序结构,跳转结构,循环结构
C. 过程结构,循环结构,分支结构
D. 过程结构,对象结构,函数结构
A
无对象结构、跳转结构、过程结构等说法。
-
哪个选项关于循环结构的描述是错误的?
A. 死循环无法退出,没有任何作用
B. 条件循环和遍历循环结构都是基本的循环结构
C. 循环是一种程序的基本控制结构
D. 循环是程序根据条件判断结果向后反复执行的一种运行方式
A
死循环能够用于测试性能,形式上的死循环可以用break来退出,例如:
x = 10 while True: x = x - 1 if x == 1: break
死循环是有其作用的。
-
关于Python语句P=-P,哪个选项的描述是正确的?
A. P的绝对值
B. P等于它的负数
C. 给P赋值为它的负数
D. P=0
C
Python中的=是赋值符号,==是判断相等性的等于符号。
-
哪个选项是用来判断当前Python语句在分支结构中?
A. 缩进
B. 冒号
C. 引号
D. 大括号
A
缩进表达层次关系。
-
哪个选项是下面代码的执行结果?
for s in "PYTHON": if s=="T": continue print(s,end="")
A. PYHON
B. PYTHON
C. PY
D. TT
A
continue结束当次循环,但不跳出当前循环。
-
哪个选项是random库中用于生成随机小数的函数?
A. randint()
B. random()
C. randrange()
D. getrandbits()
B
randint()、getrandbits()、randrange()都产生随机整数,random()产生0到1之间的随机小数。
-
关于try-except,哪个选项的描述是错误的?
A. NameError是一种异常类型
B. 使用了异常处理,程序将不会再出错
C. 表达了一种分支结构的特点
D. 用于对程序的异常进行捕捉和处理
B
使用了异常处理,程序可能运行不会出错,但逻辑上可能出错。程序错误是一个大概念,不仅指代码运行错误,更代表功能逻辑错误。
程序设计题
-
四位玫瑰数
描述
四位玫瑰数是4位数的自幂数。自幂数是指一个 n 位数,它的每个位上的数字的 n 次幂之和等于它本身。
例如:当n为3时,有1^3 + 5^3 + 3^3 = 153,153即是n为3时的一个自幂数,3位数的自幂数被称为水仙花数。
请输出所有4位数的四位玫瑰数,按照从小到大顺序,每个数字一行。
输入输出示例
输出仅表示格式,不表示对错。
输入 输出 示例 1 无
1111 2222 3333
for i in range(1000,10000):
s=str(i)
if (eval(s[0])**4+eval(s[1])**4+eval(s[2])**4+eval(s[3])**4)==i:
print(i)
---
s = ""
for i in range(1000, 10000):
t = str(i)
if pow(eval(t[0]),4) + pow(eval(t[1]),4) + pow(eval(t[2]),4) + pow(eval(t[3]),4) == i :
print(i)
-
100以内素数之和
描述
求100以内所有素数之和并输出。
素数指从大于1,且仅能被1和自己整除的整数。
提示:可以逐一判断100以内每个数是否为素数,然后求和。
输入格式
该题目没有输入
输入输出示例
输入 输出 示例 1 1234(这是示例,不是真实输出)
def judge(n):
for i in range(2,n):
if n%i==0:
return 0
return 1
ans=0
for i in range(2,101):
if judge(i):
ans+=i
print(ans)
---
#Prime
def is_prime(n):
for i in range(2,n):
if n%i == 0:
return False
return True
sum = 0
for i in range(2,100):
if is_prime(i):
sum += i
print(sum)
简单的函数使用在"天天向上的力量"实例中已经介绍过了。