程序流程控制
程序流程控制
前面我们学习了python的基本数据类型,和一些基本语法,相当于我们已经把编程语言的“字和词”学了,接下来我们开始“造句”。
python中是通过一些程序结构来控制程序的执行顺序和流程的。
一、程序结构
计算机程序是一条条按顺序执行的指令,顺序结构是计算机程序的基础,但单一的顺序结构不能解决所有问题,计算机程序由三种基本结构组成。
- 顺序结构
- 分支结构
- 循环结构
1 顺序结构
我们每天早上起床,穿衣服,洗脸,刷牙,叠被子,吃早餐,这些按照单一顺序进行的就是顺序结构。
顺序结构是程序执行的基本流程,它会按照代码从上往下依次执行。
a = 1
a += 1
print(a) # 2
例如上面的代码,执行流程为
1.创建一个整数1,赋值给a
2.变量a自加1
3.调用函数print输出变量a的值
从上往下依次执行。
2.分支结构
出门时是否带伞要根据天气条件进行判断,如果天气好就不带,如果可能下雨或者正在下雨就要带,这就是分支结构
分支结构是程序根据条件判断结果而选择不同代码向前执行的一种方式,也叫条件分支。
分支结构包括:
- 单分支
- 二分支
- 多分支
2.1 单分支
在python中单分支结构通过if语句来实现,语法如下
if <条件>:
语句块
- 注意条件语句结束后要紧跟冒号
- 语句块是if条件满足后执行的一条或多条语句序列
- 语句块中语句通过缩进与if语句所在行形成包含关系
- 缩进按照规范为4个空格
if 语句会首先计算<条件>表达式,如果结果为True则会执行所包含的语句块,结果为False则会跳过所包含的语句块
if语句中的语句执行是否依赖于条件判断,但无论什么情况,控制都会转到与if语句同级别的下一条语句。
案例:成绩是否及格(1)
input函数
用来在控制台接收用户输入的文本信息,然后以字符串的形式返回,它接收字符串参数作为提示信息输出。运行后会在控制台出现一个光标等待你的输入,输入完成后程序并没有结束,需要再按下回车才能成功。
score = input('请输入你的成绩>>>:')
print(score,type(score))
请输入你的成绩>>>:
100 <class ‘str’>
# 接收用户输入的成绩
score = input('请输入你的成绩>>>:')
# 转换类型
score = float(score)
# 判断是否不及格
if score < 60:
print('没及格,赏一巴掌')
# 判断及格了没有
if score >= 60:
print('有进步,么么哒,亲一下')
请输入你的成绩>>>:100
有进步,么么哒,亲一下。
注意:
①:用户输入的数据默认都是str类型,跟数值进行比较一定要记得做类型转换。
②:if 语句中的语句块执行与否依赖于条件判断,但无论结果如何,控制都会转到与if语句同级别的下一条语句。对于上面我们的单分支语句,如果score<60,可以打印出’没及格,赏一巴掌’但是此时代码并没有结束,还会跑到下面的if语句中进行判断,这就显得多此一举了。对于这种二选一的条件,我们使用二分支会更好一点。
2.2 二分支
python中二分支结构通过 if - else 语句来实现,语法格式如下:
if <条件>:
<语句块1>
else:
<语句块2>
- <语句块1> 是在if条件满足后执行的一个或多个语句序列
- <语句块2>是指if条件不满足后执行的语句序列
- 注意缩进,<语句块2>通过缩进与else 所在行形成包含关系。
二分支语句用于区分<条件>的两种可能True或者False,分别形成路径
案例:成绩是否及格(2)
通过二分支改进案例-成绩是否及格
# 接收用户输入
score = input('请输入你的成绩>>>:')
# 转换类型
score = float(score)
# 判断
if score < 60:
print('没及格,赏一巴掌')
else:
print('有进步,么么哒,亲一下')
请输入你的成绩>>> :59
没及格,赏一巴掌 二选一,这个时候就不会再去执行下面的判断了
当我们有两条路要走的时候,要么成立要么不成立, 要用二分支。
三目运算
二分支结构还有一种更简洁的表达方式,语法格式如下。
<表达式> if <条件> else <表达式2>
适合代码块为1行语句时,这种方式也叫做三目运算
上面的代码可以改写为
score = input('请输入你的成绩>>>:')
# 转换类型
score = float(score)
# 判断
print('没及格,赏一巴掌') if score < 60 else print('有进步,么么哒,亲一下')
# 等价于上面的语法
请输入你的成绩 >>>:100
有进步,么么哒,亲一下
当我们二分支里面的语句块都只有一行的时候,我们就可以用三目运算,看起来会更加的简洁。
2.3 多分支
python通过 if -elif - else 表示多分支结构,语法如下
if <条件1>:
<代码块1>
elif <条件2>:
<代码块2>
...
else:
<代码块3>
多分支是二分支的扩展,用于判断条件多条执行路径的情况,python会从上往下,依次执行判断结果,寻找第一个结果为True的条件,执行该条件下的语句块,同时跳出整个 if- elif -else 语句,执行后面的语句,如果没有任何条件成立,则执行else下的代码块,且else语句是可选的,也就是说可以没有else语句 只会选一条路。
案例:成绩评价
上面的案例对成绩的评价太粗糙了,60分就可以赏个么么哒,通过多分支改进上面的案例:
请根据用户输入的成绩,按等级分区:
- <40 :E
- 40 - 60: D
- 60 -75 :C
- 75 -85 :B
- 85- 100 :A
score = input('请输入你的成绩>>>:')
# 转换类型
score = float(score)
# 判断
if score < 40:
print('等级:E')
elif 40 <= score < 60:
print('等级:D')
elif 60 <= score < 75:
print('等级:C')
elif 75 <= score < 85:
print('等级:B')
else:
print('等级:A')
请输入你的成绩>>>:100
等级A
注意:条件写的顺序是很重要的,要有逻辑。多分支,尽量做到条件之间互斥。
补充:
res = {'code':0, 'msg':'参数错误'}
if res['code'] == 0:
print('请求错误')
else:
print('请求成功')
上面的代码还可以这样写:
if res['code']: # 默认会去计算一下它的布尔值
print('请求成功')
else:
print('请求错误')
当我们直接在if后面写某个变量或值的时候,它等价于 if bool(res['code']): 把它布尔一下。
code值为0,布尔一下就是False。输出'请求错误'
注意: if 后面的条件是True 后面的语句块才会执行。
2.4 debug技能
- step over:执行下一步
- rerun:重新执行当前.py文件
- stop: 停止执行
3 循环结构
工作日每天9:00到公司上班,17:30下班,这就是循环结构。
python中循环结构有两种
1.条件循环也叫while循环
2.遍历循环也叫for循环
3.1 while 条件循环
python中的条件循环通过while循环语句来实现,所以也叫做while循环,语法格式如下。为什么叫条件循环呢?因为它每次循环的时候都需要判断条件。
当条件为True时会循环执行代码块,直到条件为False就会跳出循环。
while循环 使用场景:你不明确循环的次数
while <条件>:
代码块
- while关键字空格后接条件表达式末尾加上冒号组成whlie语句。
- 代码块中的代码通过4个空格和while语句形成包含关系
while语句首先计算<条件>表达式,如果结果为True,则执行对应代码块中的语句,执行结束后再次执行<条件>表达式,再次判断结果,若结果仍为True则循环执行,直到<条件>表达式为False时,跳出循环,执行和whlie语句相同缩进的下一句语句。
当条件表达式恒为True时,形成无限循环,也叫死循环,需要小心使用。
例1:
# 依次打印0-9
i = 0
while i < 10:
print(i)
i += 1 # 改变条件的语句
0
1
2
3
4
5
6
7
8
9
注意: while 循环一定要设置退出条件,不然就是死循环。
例2 : 循环序列
# 循环打印列表里面的值
# 序列都可以这样去循环
ls = ['a','b','c','d','e','f']
index = 0 初始索引
while index < len(ls):
print(index,ls[index])
index += 1
0 a
1 b
2 c
3 d
4 e
5 f
序列都可以用这种方式去循环
循环散列 ?
能否用while循环,去循环集合?
能否用while循环,去循环字典?
例3:集合 必须先转化成列表才能去循环
set = {'q', 'a', 'r', 'b'}
ls = list(set)
index = 0
while index < len(ls):
print(index, ls[index])
index += 1
0 b
1 q
2 a
3 r
例4 : 使用while循环循环字典
字典:取出key形成列表,去循环
dict.keys() 方法返回字典的key # 会返回字典的key组成的类列表对象,dict_keys(['name', 'age', 'height']) 可以用列表转化一下,会变成一个列表
dict.values() 返回字典的值组成的类列表对象 # 可以用list转化成列表
dict.items() 返回字典的键值对组成的类列表对象 会返回一个二元元组组成的列表
print(list(dc.items())) [('name', '心蓝'), ('age', 18), ('height', 170)]
1,遍历字典的key dc.keys()
dc = {'name': '心蓝', 'age': 18, 'height': 170}
keys = list(dc.keys()) # 拿到字典中所有的键组成的列表
index = 0
while index < len(keys):
print(index, keys[index], dc[keys[index]])
index += 1
0 name 心蓝
1 age 18
2 height 170
2,遍历字典的values 两种方法
(1) dc.values
dc = {'name': '心蓝', 'age': 18, 'height': 170}
values = list(dc.values()) # 拿到字典中所有的values组成的列表
index = 0
while index < len(values):
print(index, values[index])
index += 1
0 心蓝
1 18
2 170
(2)
dc = {'name': '心蓝', 'age': 18, 'height': 170}
keys = list(dc.keys()) # 拿到字典中所有的键组成的列表
index = 0
while index < len(keys):
print(index,dc[keys[index]])
index += 1
0 心蓝
1 18
2 170
怎么循环出字典的键值对呢?
dict.items() 返回字典的键值对
dc = {'name': '心蓝', 'age': 18, 'height': 170}
key_value = list(dc.items())
print(key_value)
# [('name', '心蓝'), ('age', 18), ('height', 170)]
index = 0
while index < len(key_value):
print(key_value[index][0], key_value[index][1])
index += 1
while True: 无限循环
3.2 for 遍历循环
python中使用关键字for来实现遍历循环,也叫for循环,也叫迭代循环,语法格式如下:
for <循环变量> in <遍历结构>:
代码块
代码当遇到for循环的时候会在遍历结构里面依次取出里面的元素然后交给循环变量,每次都会执行一下代码块,直到把遍历结构里面的所有元素都循环到,然后跳出循环。
- 关键字for + 空格 + <循环变量> + 关键字 in + <遍历结构> + 冒号组成for语句
- 代码块通过缩进和for语句形成包含关系
- 循环变量其实就是普通的变量,名字可以随意定。
所有的可迭代对象都可以作为遍历结构进行for循环
基本数据类型中的序列类型,散列类型都可以进行迭代。
for循环:使用场景,明确需要循环的次数
例1:
# for循环用来遍历可迭代对象非常方便
# 序列的迭代
# 列表的迭代
ls = [0,1,2,3,4,5,6,7,8,9]
for i in ls: # 相当于 i = list_1[0] ...直到取完
print(i)
i : 代词: 可迭代对象中的元素轮流赋值给i
循环次数:就是可迭代对象 元素的个数
0
1
2
3
4
5
6
7
8
9
例2:
# 散列的迭代
st = {1,2,3,4,5,6}
for i in st:
print(i)
1
2
3
4
5
6
例3 : 字典kye和值的迭代,一般情况下都这样用。
dc = {'name': 'xinlan', 'age': 18}
# 字典key的迭代
for key in dc:
print(key,dc[key])
name xinlan
ag 18
注意:直接用for循环迭代字典的时候,迭代的是字典的key。
例4: 字典值的迭代(1)
# 字典值的迭代
dc = {'name': 'xinlan', 'age': 18}
for key in dc:
print(dc[key]) # dc[key]就是取key下的值
xinlan
18
字典值的迭代(2)
dc = {'name': 'xinlan', 'age': 18}
for value in dc.values():
print(value)
xinlan
18
判断key或value是否在dict中,使用成员运算符。
- 判断字典中是否有这个键
dc = {'name': 'xinlan', 'age': 18}
print('name' in dc) # True
- 判断字典中是否有这个值
dc = {'name': 'xinlan', 'age': 18}
print('xinlan' in dc.values()) # True
总结:
①:直接用for循环循环字典的时候,迭代的是字典的key
②:循环变量其实就是普通的变量,名字可以随意定
③:在字典中直接使用成员运算符,检查的是字典的key
例题:(字典遍历)当前有一个字典{“a”:1,“b”:22,“c”:3,“d”:4,“e”:5 },
请修改字典中所有键值对的值,新的值为原来的值乘10
dic = {"a": 1, "b": 22, "c": 3, "d": 4, "e": 5}
for key in dic:
dic[key] = dic[key] * 10
print('修改后的字典:', dic)
# 修改后的字典: {'a': 10, 'b': 220, 'c': 30, 'd': 40, 'e': 50}
while 循环和for循环的区别
num = 0
while num <= 10:
print(num)
num += 1
for i in range(11):
print(i)
这两种写法的效果是一样的
for循环:能明确循环次数
while循环:不明确循环次数,一定要写退出条件
循环的应用
for 循环常用(基本上不会超过2层循环)
while 循环基本不用
迭代器(iterator)
迭代器是一个可以记住遍历位置的对象,for循环本质上就是通过迭代器来实现的。
通过内建函数 iter 可以创建迭代器
for char in 'abc': # for char in iter('abc)
print(char)
a
b
c
字符串没办法直接去获取字符串中的每一个值,本质上是调用了iter函数,for char in 'abc 等同于 for char in iter('abc),会返回一个迭代器,这个迭代器可以记住遍历的位置。
不是所有的数据类型都可以创建迭代器,凡是能够被iter()执行的数据类型都是可迭代的,那么它就可以被for循环,反之就是不可迭代的,凡是能够创建迭代器的对象称为可迭代对象,反之是不可迭代对象。
print(iter('abc'))
# <str_iterator object at 0x000001B1179BC748>
- 字符串,列表,元祖,集合,字典都是可迭代对象(可迭代:把里面的元素一个一个取出来)
range 函数
内建函数range可以创建输出整数序列的迭代器
range是python中内置的一种序列(支持索引取值和切片操作)
语法:
- `range([start], end,[step])
start指的是计数起始值,默认是0
end 指的是计数结束值,但不包括end (必传参)
step是步长,默认为1,不可以为0,可以为正数或负数。
range() 方法生成一段左闭右开的整数范围。
注意:只传一个值默认代表的是end,end是必传参数。star 和 step都有默认值
用法:
-
range(n) :默认生成一个0到n-1的整数序列,对于这个整数序列,我们可以通过list()函数转化为列表类型的数据
-
-
range(n,m):默认生成一个n到n-1的整数序列(左闭右开),对于这个整数序列,我们可以通过list()函数转化为列表类型
- -
range(n,m,k): 相当于其他函数里面的for循环,n初始值,m结束值,k步长,会生成初始值为n,结束值为m-1,递减或者是递增的整数序列。
想生成 13579
例1 :
# 输出0-9
for i in range(10):
print(i)
例2 :
# 输出1-10
for i in range(1,11):
print(i)
例3
# 输出-1 - -10
for i in range(-1,-11,-1):
print(i)
注意:
①:表示的是左闭右开
②:它接收的参数必须是整数,可以是负数,但不能是浮点数等其他类型
③:它是不可变的序列类型,可以进行判断元素,查找元素,切片等操作,但是不能修改。
④:它是可迭代对象,不是迭代器。
⑤:分隔符是逗号(英文),注意和切片(冒号)区分。
- for i in range(n):
这是一个固定用法,用来控制循环次数
for i in range(10):
print(i)
for循环经常和range函数配合起来用来指定循环次数。
应用场景:循环100次
for i in range(1, 101):
print('打印{}遍hello, world!'.format(i))
3.3 循环控制关键字
作用:主动结束循环
循环有时候需要主动中断来提高程序执行效率
ls = [60,59,78,80,56,55]
# ls中存放的是所有学生的成绩
# 要判断是否有同学不及格
for score in ls:
if score < 60:
print('有同学不及格')
有同学不及格
有同学不及格
有同学不及格
可以发现上面的案例中,其实第二个同学成绩就不合格了,但是程序继续循环下去,如果数据量小,效率差别不大,但数据量大时会影响程序的执行效率,在实际的代码编写中会有很多这种情况,这就需要能够主动结束循环的能力。
break 关键字 (跳槽)
break 关键字会结束当前循环(执行循环之外的代码)
例1
ls = [60,59,78,80,56,55]
for score in ls:
if score >= 60:
print('有同学及格')
break
有同学及格
for i in range(10):
print(i)
if i == 5:
break
0
1
2
3
4
5
break 关键字既针对for循环也可以针对while循环
ls = [60, 59, 78, 80, 56, 55]
index = 0
while index < len(ls):
if ls[index] < 60:
print('有同学不及格')
break
index += 1
有同学不及格
总结:break关键字会结束当前循环,只会跳出一层,循环可能有多层-循环嵌套
循环嵌套
循环里套循环
for 循环和for循环嵌套。
for i in range(10):
for j in range(10):
print(i,j) # 类似于笛卡尔连接(交叉连接)
第一层循环跑一次,第二层循环要全部跑完
每一个内层循环要跟所有外层循环匹配一次
可以通过打断点去看程序的运行流程
把上面的例子转换成下面的代码会更好理解
例:
man =['周先生','吴先生','郑先生','王先生','赵先生','钱先生','孙先生','李先生','冯先生']
women=['周女士','吴女士','郑女士','王女士','赵女士','钱女士','孙女士','李女士','冯女士']
for m in man:
for w in women:
print(m,w)
# 两两组合,一起相亲,列表man里面每一位男嘉宾都要跟woren里面的女嘉宾相一次
需求,两层循环打印6*6的正方形。
for i in range(6):
for j in range(6):
print('* ',end ='') # print('*', end ='') # 输出时加参数 end = '', 让下一次执行print输出不换行
print()
# print()的作用是让每执行完一次外层循环之后换行。
实现了利用双重for循环打印任意比例的正方形
外层循环控制的是列,内层循环控制的是行
相当于循环里面套循环,外层循环每执行一次,执行一次里面循环。
需求:打印乘法口诀表
continue 关键字 (请假)
循环中还有这种情况,跳出当次循环
关键字continue跳出当次循环,也就是说continue下的语句不执行了,再去循环下一次。
例1:
man =['周先生','吴先生','郑先生','王先生','赵先生','钱先生','孙先生','李先生','冯先生']
woman=['周女士','吴女士','郑女士','王女士','赵女士','钱女士','孙女士','李女士','冯女士']
# 两两组合,一起相亲。
# 同姓别的不组合
for m in man:
for w in women:
if m[0] == w[0]:
continue
print(m,w)
# 也可以写成
if m[0] != w[0]:
print(m,w)
for i in range(10):
if i == 5:
continue
print(i)
0
1
2
3
4
6
7
8
9
break 和 continue的区别
遇到continue关键字,本次循环跳过,开始执行下一次循环
遇到break关键字,结束整个循环语句。
list_1 = ['a', 'b', 'c', 'd']
for i in list_1:
if i == 'c':
break
print(i) # a,b
#
list_1 = ['a', 'b', 'c', 'd']
for i in list_1:
if i == 'c':
continue
print(i) # a,b,d
- break只会跳出一层循环
for i in range(3):
for j in range(4):
if i == 1:
break
print(i, j)
0 0
0 1
0 2
0 3
2 0
2 1
2 2
2 3
- continue 跳出当次循环
打印所有的奇数
for i in range(10):
if i % 2 == 0:
continue
print(i) # 输出 1.3.5.7.9
for i in range(10):
if i % 2 == 0:
break
print(i) # 无输出 因为取值范围为 0-9 起始值是0, 0%2=0 触发break直接跳出
else 关键字 (年终奖)
一个循环可能半路就被干掉了(一个循环没有循环完毕)
else 关键字,可以判断一个循环是正常结束,还是出了意外
for i in range(10):
if i%2 != 0:
continue
print(i)
else:
print('循环正常结束')
0
2
4
6
8
循环正常结束
for i in range(10):
if i%2 != 0:
break
print(i)
else:
print('循环正常结束')
0
凡是有break的循环,不会执行else中的语句。
3.4 异常处理
要掌握两个能力
1, 异常分析
2,异常捕获
- 异常分析
先看异常类型,再看异常提示,再看异常溯源信息。
- 异常捕获
try:
有可能会出错的代码
except
代码错误了执行的代码(对异常处理) 捕获到错误并进行处理
try:(对于那些有可能因为给的数据有问题而发生错误的代码,用try把它包裹起来,就是叫’踹它‘,相当于一个检测功能,监测代码运行是否报错’ 如果报错,正常情况下,程序就崩掉了就没办法继续往下执行了)
但如果代码报错了,我不希望我的这个程序崩掉,我希望程序正常地继续往下执行,那我们就把可能出错的代码放在try里面,当代码出错后会输出except中的语句 。
当不同的异常要做不同的处理的时候可以去指定异常类型
这个其实和前面条件判断的if-else语句是差不多的,当我try里面的代码报错了,它会去判断一下这个错误是什么类型,如果是NameError这个类型,那么好,我做这个处理,如果不是这个类型的错误,它会去判断是不是下一个类型错误,如果还不是它会继续往下面走,如果是的会处理,如果找不到会直接抛出异常,这个except跟if-elif-else类似,只要有一个成立,它就不会执行下面的except了,这个except根据你的需求可以写多个,如果上面的代码都没有报错的情况下,它会执行else。如果这个异常类型不是你所捕获的异常类型,那么它会直接抛出异常,该报什么错还报什么错
需求:如果你事先不知道异常类型的时候想去捕获应该怎么捕获呢
直接写except可以捕获所有的异常
捕获异常之后获取异常信息
获取捕获到的异常的异常信息,并把它赋值给e这个变量,然后通过打印e这个变脸去获取到前面这个代码报的错究竟是什么样的错误。
如果你不知道它的异常类型,通过Exception ,它是所有异常的父类,你写一个Exception和写一个except后面不写异常是一样的,相当于捕获所有的异常类型,然后把所有的异常信息获取到。
总结:
try:
写有可能会出现异常的代码,如果try监测到异常后就会执行except
except :
可以对try中代码所报的异常,做相关的处理。
else:
try 里面的代码没有出现异常的时候会执行
finally:
只要执行了try里面的代码就一定会执行finally(不管有没有异常都会执行)
需求:用户输入一个数值n,打印1到n(包含n)之间所有的偶数、及其偶数个数、及其它们的平均值(如果输入非数值,请让用户重新输入)
提示:异常处理+循环实现