抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

image-20210521125048404

第九章 不定循环:while循环

9.1 (回顾)用户输入与for循环

9.1.1 用户输入

任务一:用户输入input()函数

知识点:接收用户输入

语法:input([prompt])

描述:程序会一直等待用户输入,直到用户按回车键后继续运行

参数:(可选) prompt为字符串类型,用于提示输入信息

返回:字符串类型

当等待输入时,程序会被中断/阻塞(cell的左边In[*]),直到接收输入后程序才能继续运行

注意:此中断是全局的,即会影响当前整个jupyter程序的其他cell,导致其他cell运行程序时也会出现In[*]

input()函数的程序中断测试

首先运行下面的输入程序,不输入,此时程序会阻塞,左边出现In[*]

再运行其他cell的程序程序,会发现其他cell程序也会被中断,左边出现In[*]

然后在**input()**函数的cell中输入数据之后,程序的阻塞会被解除。此时,其他cell的程序也恢复了正常

1
2
# 首先运行这个cell,不输入任何东西
a = input("请输入:")
1
2
# 然后 运行这个cell,会发现程序被中断
print('只有在解除中断之后,才能运行该cell')

任务二:多次运行带input()的cell

知识点:

多次运行带**input()的cell,不接受用户输入,整个jupyter将会卡死,此时input()**输入框也会消失

为此,需要手动重启kernel:Kernel–> Restart

多次运行下面cell,然后通过手动重启kernel来重置Python解释器

1
2
# 首先运行这个cell,不输入任何东西
a = input("请输入:")

任务三:input()函数的的返回是字符串

知识点(回顾):

**input()**函数的返回是字符串类型

如果直接对返回值进行数值运算,会引起异常TypeError

为此,需要对返回值显式地调用类型转换函数,例如:**int()、float()**等

1
2
3
4
5
a = input("请输入整形:")
print(type(a), a)

b = int(a)
print(type(b), b)

任务四:求模运算符(%)

知识点:

求模运算符(%)将两个数相除并返回余数

如果一个数可被另一个数整除,余数就为0,因此**%**将返回0

1
2
3
4
print(4 % 3)
print(5 % 3)
print(6 % 3)
print(7 % 3)

奇偶数判断程序。偶数都能被2整除,因此对number和2执行求模运算的结果为零,即number % 2 == 0;否则就是奇数

1
2
3
4
5
6
number = int(input("输入整数:"))

if number % 2 == 0:
print(f"数字{number}为偶数。")
else:
print(f"数字{number}为奇数。")

习题:

7-1 汽车租赁:编写一个程序,询问用户要租赁什么样的汽车,并打印一条消息,如“Let me see if I can find you a Subaru”

1
2
3
car='What kind of car do you need?'
kids=input(car)
print('let me see if can find you a '+kids)
1
let me see if can find you a Benz

7-2 餐馆订位:编写一个程序,询问用户有多少人用餐。如果超过8人,就打印一条消息,指出没有空桌;否则指出有空桌

1
2
3
4
5
6
7
inquiry='How many people have dinner, please?'
num=input(inquiry) # 3
num=int(num)
if num>8:
print('There are no empty tables')
else:
print('There is a table available')
1
There is a table available

7-3 10的整数倍:让用户输入一个数字,并指出这个数字是否是10的整数倍

1
2
3
4
5
6
7
8
9
num='plese input one number:'
nums=input(num) # 20
nums=int(nums)
if nums%10==0:
nums=str(nums)
print(nums+' is an integral multiple of ten')
else:
nums = str(nums)
print(nums+' is not inteqral multiple of ten')
1
20 is an integral multiple of ten

9.1.2 程序的三大流程

任务一:掌握程序开发的三大流程

在程序开发中,一共有三种流程方式:

顺序:从上向下,顺序执行代码

分支:根据条件判断,决定执行代码的分支

循环:让 特定代码块重复 执行

9.1.3 确定循环:for循环

任务一:回顾for循环

for循环语法:

1
2
for item in <sequence>:
<statements>

知识点:回顾请看第4章

描述: for循环用于遍历序列或集合类型对象(列表、元组、字典、字符串等),在循环体中实现对每个元素执行批量操作

在每次迭代中,循环临时变量item依次获取序列****中的元素

然后,循环体**针对每个item**执行一次

思考:for语句的循环次数是多少?

任务二:for循环的不足

需求分析:编写一个程序,计算用户输入的一系列数的平均值

平均值:数的和除以数的个数

为了让程序通用,它应该适用于任意数量的数

思路:

首先询问用户总共有几个数,通过input()输入一个总数量n

然后使用循环,通过input()接受用户输入的n个数,然后依次对它们进行累积total。

循环结束后对total除以n求平均

算法伪代码:

1
2
3
4
5
6
input()输入总共有n个数
初始化 total = 0
循环 n 次
  input()输入数x
  total += x
求均值 average = total / n

根据伪代码,直接转换为Python程序:

1
2
3
4
5
6
n = int(input("共有多个数?"))
total = 0.0
for i in range(n):
x = float(input("输入数字:"))
total += x
print("均值为:", total / n)

缺陷分析:

上述的求平均值程序肯定是有效的,但是它的人机交互存在缺陷

它首先需要询问用户有多少个数字。数字较少时,用户可以数一数输入的数字规模。但如果有很多很多的数需要求平均值,那么把所有的数都数一遍是不太可行的

造成这现象的原因是for循环需要提前明确循环次数。换言之,for循环是有限的确定循环

9.2 不定循环:while循环

9.2.1 while循环语法

任务一:while循环的流程分析

需求分析:

循环的作用就是让指定的代码在满足一定的条件下重复的执行

while 循环最常用的应用场景就是让执行的代码根据指定的条件来重复执行

需求:打印 5 遍 Hello Python

思考:如果要求打印 100 遍怎么办?

while循环的伪代码:

1
2
3
4
5
6
7
8
9
初始条件设置 —— 通常是重复执行的 计数器

while 条件(判断 计数器 是否达到 目标次数):
条件满足时,做的事情1
条件满足时,做的事情2
条件满足时,做的事情3
...(省略)...

处理条件(计数器 + 1)

知识点:

while 语句以及缩进部分是一个完整的代码块

while循环通过判断条件来决定循环是否执行,因此它适用于指定次数(for循环擅长做)和不指定次数(for循环不擅长做)的场景

任务二:while循环语法

需求分析:

for循环是一个有限的确定循环。即定义for循环时,必须确定迭代次数

for循环求平均数程序中,如果不让用户提前输入总数量,那么程序就无法知道循环迭代次数。这导致程序设计陷入了困境

如何让程序拥有自动计数功能?

while循环语法:

1
2
while <condition>:
  <statements>

知识点:

Python提供了不定循环条件循环机制——while循环

类似于if语句,while循环使用****布尔表达式来控制循环

只要条件为True,循环体**就会重复执行;当条件为false**时,循环终止

while循环不需明确循环次数,它通过**来控制循环的运行。因此,相对确定循环for语句,它被称为不定循环**

先测试的循环结构:

while循环体执行之前****条件

如果循环**最初为False,则循环体**就根本不会被执行

该循环结构,循环次数**>=0**次,最少为0次

使用while实现5、4、3、2、1倒计时打印

1
2
3
4
5
a = 5
# a > 0为循环条件
while (a > 0):
print(a)
a -= 1

任务三: while循环实现循环打印

打印5遍 Hello Python

1
2
3
4
5
6
7
8
9
10
11
12
13
# 1. 定义重复次数计数器
i = 1

# 2. 使用 while 判断条件
while i <= 5:
# 要重复执行的代码
print("Hello Python")

# 处理计数器 i
i = i + 1

# print("循环结束后的 i = %d" % i)
print("循环结束后的 i = {i}") # f-string方式

注意:循环结束后,之前定义的计数器变量i是依旧存在的

任务四:赋值运算符

知识点:

在 Python 中,使用 = 可以给变量赋值

在算术运算时,为了简化代码的编写,Python 还提供了一系列的与算术运算符 对应的赋值运算符

注意:赋值运算符中间不能使用空格

运算符 描述 实例
= 简单的赋值运算符 c = a + b
+= 加法赋值运算符 c += a 等效于 c = c + a
-= 减法赋值运算符 c -= a 等效于 c = c - a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
//= 取整除赋值运算符 c //= a 等效于 c = c // a
%= 取模 (余数)赋值运算符 c %= a 等效于 c = c % a
**= 幂赋值运算符 c* *=a 等效于 c=c**a

任务五:Python 中的计数方法

常见的计数方法有两种,可以分别称为:

自然计数法(从 1 开始)—— 更符合人类的习惯

程序计数法(从 0 开始)—— 几乎所有的程序语言都选择从0开始计数

因此,在编写程序时,应养成习惯:除非需求的特殊要求,否则循环的计数都从0开始

9.2.2 实例:while循环计算求和

任务一:循环实现累加求和

需求分析:在程序开发中,通常会遇到利用循环,进行重复计算(比如求和)的需求

通常需要在 while循环之前先定义一个变量,用于存放累积的计算结果

然后,在循环体内部,根据计算结果对该变量进行更新

计算0~100之间所有数字的累计求和结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 计算 0 ~ 100 之间所有数字的累计求和结果
# 0. 定义最终结果的变量
result = 0

# 1. 定义一个整数的变量记录循环的次数
i = 0

# 2. 开始循环
while i <= 100:
print(i)

# 每一次循环,都让 result 这个变量和 i 这个计数器相加
result += i

# 处理计数器
i += 1

print(f"0~100之间的数字求和结果 = {result}")

任务二:循环实现偶数累加求和

计算0~100之间所有偶数的累计求和结果。在之前的程序基础上,添加奇偶判断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 0. 最终结果
result = 0

# 1. 计数器
i = 0

# 2. 开始循环
while i <= 100:

# 判断偶数
if i % 2 == 0:
print(i)
result += i

# 处理计数器
i += 1

print(f"0~100之间的数字求和结果 = {result}")

9.2.3 循环变量

知识点(术语):循环变量

while循环需要通过一个额外的循环变量来控制循环流程

通过循环变量来检验****是否满足

在循环体中,需要对循环变量进行更新

任务一:认识循环变量

下面是一个简单的while循环,按步长为2,从1数到9

1
2
3
4
5
6
#循环变量为a
a = 1
while a < 10:
print(a)
# 朝循环终止条件更新a
a += 2

a称为循环变量,用来控制循环

在第1行,将循环变量a设置为1,从而指定从1开始数

接下来的while循环被设置成这样:只要a < 10,就执行循环体

循环体中打印print(a)的值,再更新循环变量a += 2(a = a + 2的简写)

只要满足条件a < 10,就继续循环。下图对while循环每步运行进行可视化

上面while代码的输出与下面的for循环等价

1
2
for a in range(1,10,2):
print(a)

程序解析:

while循环要求在循环之前负责初始化a,并在循环体的底部让a增加,不需要指定循环迭代次数

for循环中,循环临时变量a是自动处理的,迭代次数由**range()**生成的序列来决定

知识点:循环变量可以是显式的定义变量,也可以是隐式的,例如列表的长度等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
numbers = [12, 37, 5, 42, 8, 3]
even = []
odd = []
# 将列表长度作为循环变量
while len(numbers) > 0:
#通过pop()将numbers尾部元素弹出
# 本质上朝条件更新循环变量的
number = numbers.pop()
# 奇偶判断
if (number%2==0):
even.append(number)
else:
odd.append(number)

print(even)
print(odd)

9.2.4 无限循环

任务一:while循环容易导致死循环

知识点:由于程序员的原因,忘记在循环内部修改循环的判断条件,导致循环持续执行(无限循环),程序无法终止!

知识点:不恰当的使用循环变量容易导致无限循环

由于while循环的终止条件是通过来控制的,使得while循环功能强大,它可以处理非序列或集合类型的循环

while循环每次通过循环变量a来判断是否满足

在循环体中,如果不恰当或忘记更新循环变量a,将会造成程序无限循环,cell一直*In[]**状态

1
2
3
4
# 忘记更新a导致无限循环
a = 1
while a < 10:
print(a)

程序解析:

当Python到达while循环时,a是1,小于10,所以循环体执行,打印1

现在控制变量a返回到条件,a仍是1,所以循环体再次执行,打印1

现在控制返回到条件,a仍是0,所以循环体再次执行,打印1…… (死循环)

1
2
3
4
5
# 不恰当更新a导致无限循环
a = 1
while a < 10:
print(a)
a -= 2

程序解析:

当Python到达while循环时,a是1,小于10,所以循环体执行,打印1

现在控制变量a返回到条件,a是-1,所以循环体再次执行,打印-1

现在控制返回到条件,a是-3,所以循环体再次执行,打印-3…… (死循环)

知识点:

作为初学者,很容易一不小心会写出无限循环程序,这是通往高手的必经之路

如果出现无限循环,要检查循环变量的更新是否是朝终止条件的

换言之,循环变量的更新是否收敛于循环控制条件

出现无限循环是,Jupyter通过Kernel–>Interrupt进行重置

9.3 常见循环模式

9.3.1 交互式循环

任务一:交互式循环

知识点:

不定循环while可以实现程序与用户的交互式循环

所谓的交互式循环,就是在while循环期间,程序通过不断询问用户,来决定是否继续循环

下面将通过数字平均值求解来分析交互式循环的机制

需求分析:

回忆,该程序之前需要强制用户提前输入一个需要参与运算数字的总数

为此,希望while循环能自动记录这个数。定义变量count来实现计数功能,初识从0开始,每次循环增加1

交互式循环:为了允许用户可以控制循环是否结束,在每次迭代过程中,程序都将交互式地询问用户是否还有数据要处理

交互式循环通用算法流程描述如下,其中moredata为循环循环变量

1
2
3
4
5
设置 moredata 为 "yes"
while (moredata 是否 "yes")
  获得 the next data item
  处理 the item
  询问用户是否有还有数据要处理,来控制moredata

将交互式循环与计数器count相结合,得到这个平均值程序算法的伪代码

1
2
3
4
5
6
7
8
9
初始 total to 0.0
初始 count to 0
设置 moredata to "yes"
while moredata is "yes"
  input a number, x
  total += x
  count += 1
  ask user if there is moredata
输出 total / count

根据上面的伪代码,转换为Python程序:

1
2
3
4
5
6
7
8
9
10
total = 0.0
count = 0
moredata = "yes"
while moredata[0] == "y":
x = float(input("输入数字:"))
total += x
count += 1
moredata = input("是否有额外数字需要处理 (yes or no)? ")

print("\n平均数为:", total / count)

程序解析:

使用total变量来累加求和;使用count变量来统计用户输入数据的数量

使用moredata来控制循环,while循环判断条件**moredata[0] == “y”为用户输入的字符串第一个字母是否为“y”。例如,“y”、”yes”、”yeah”等。对于非“y”**开始的字符串,则终止循环

缺陷:在这个版本中,虽然用户不必对数据量提前进行计数,但是人机交互不太友好,很繁琐,程序要不断地询问用户是否有输入

9.3.2 哨兵式循环(重要)

需求分析:

上面程序虽然实现了while循环能自动提供计数功能,但它在每次迭代中询问用户是否有数据输入,人机交互非常繁琐

如果程序能根据输入的数据本身特点来控制循环是否继续,就可以避免显式地询问用户的步骤,这种模式称为哨兵式循环

任务一:哨兵式循环

知识点:

哨兵式循环:循环体中,不断接收新数据,直到用户输入某些特殊值,表明迭代结束。例如,程序需要输入**>=0的整数,根据数据特点,如果用户输入<0**的数,就可以将它作为循环终止条件

哨兵(sentinel):可以选择任何数据值作为哨兵,唯一的限制是能与实际数据值区分开来。例如,正常数据为**>=0的整数,那么<0**的数就可以作为哨兵。

哨兵式循环通用算法流程描述如下

1
2
3
4
输入 the first item
while (item 是否为 哨兵)
  处理 the item
  输入 the next item

说明:

在循环开始之前要求用户输入第一项数据item,称为“启动输入”

如果第一项是哨兵,while循环将立即终止。否则,进入循环体,处理该项数据item,并读取下一项

在下次循环开始前,while的循环条件会判断上次输入的item是否为哨兵,来控制循环是否继续被执行。如果遇到哨兵,循环终止

启动输入循环体内的输入是一样的,都是用于接受新数据

将哨兵式循环用于数字平均值计算问题。首先要选择哨兵,即循环终止条件。假设数据是来源于期末考试成绩,通常成绩都是**>=0的。因此,可以选用<0**作为哨兵。具体Python程序如下:

1
2
3
4
5
6
7
8
9
10
11
total = 0.0
count = 0
x = float(input("输入数字(负数退出循环):"))

# x<0 作为哨兵
while x >= 0:
total = total + x
count = count + 1
x = float(input("输入数字(负数退出循环):"))

print("平均值:", total / count)

程序解析:

相比于交互式循环,哨兵式循环的用户交互简单易用,省去了一直输入yes的麻烦

x = float(input(“输入数字(负数退出循环):”)):while循环体外的启动输入循环体内的输入是一样的,都是用于接受新数据。哨兵式循环需要在while循环外,提前接受一项数据

while x >= 0,此时哨兵为x<0,即循环结束条件

缺陷:该程序不能用于对一组既包含负值又包含正值的数字求平均值

任务二:扩大哨兵范围

需求分析:

为了使得问题能处理任何范围的数值输入,需要拥有一个真正独特的哨兵

首先可以将用户的输入作为字符串来获取,并定义一个特殊的非数字字符串(比如空字符串**””“Q”“q”**),作为循环结束标识(哨兵)

其他的数值类型输入都将被转换为数字,用于计算

一个空字符串在Python中被表示为**””(不含空格)。如果用户输入空白行(只需输入),Python将返回一个空字符串。可以使用“”**作为哨兵,来改进平均数计算程序。Python程序如下:

1
2
3
4
5
6
7
8
9
10
11
total = 0.0
count = 0
xStr = input("输入数字(<Enter>退出循环):")

# 哨兵为 空字符串
while xStr != "":
x = float(xStr)
total = total + x
count = count + 1
xStr = input("输入数字(<Enter>退出循环):")
print("平均值:", total / count)

这段代码检查并确保输入不是哨兵**””后,然后将输入转换成浮点数float**用于均值计算

9.3.3 使用Flag来控制循环(重要)

任务一:掌握为何需要使用Flag

需求分析:

while循环的执行依赖于循环条件

之前,影响循环条件的都只有1个变量。然而,某些循环场景往往又会受到多个变量的同时影响,即有多个变量会影响循环的终止。例如,游戏程序中,游戏失败往往会有多个触发条件

如果while循环在一条语句中同时检测所有条件,将会导致程序变得非常复杂

本质上,就是有多个哨兵时,程序如何来控制循环条件

知识点:循环控制标志(Flag)

为了解决上述问题,可以定义一个bool类型的变量Flag作为循环控制标志,用于监测(判断)循环是否处于活跃状态

它充当了程序的信号灯作用,如果FlagTrue,说明程序是活跃状态,可以继续执行循环;如果是False,那么有循环终止事件被触发了,它将终止循环

多个循环影响因素(哨兵)可以通过Flag间接的来控制循环的执行

while循环条件中,只需要检查Flag是否为True。而触发Flag值为False的事件(哨兵)可以放在循环体的其他地方。从而使得程序整个逻辑变得更清晰

下面的程序,将上节的平均值计算程序添加一个Flag变量,来控制while循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
total = 0.0
count = 0

Flag = True
# 哨兵为 空字符串
while Flag:
xStr = input("输入数字(<Enter>退出循环):")

# 哨兵1:输入不为空
if (xStr == ''):
Flag = False
else:
x = float(xStr)
total += x
count += 1
# 哨兵2:总数不超过9
if count > 9:
Flag = False


if (count != 0):
print("平均值:", total / count)
else:
print("没输入任何数!")

程序解析:

定义一个Flag变量,使用它来作为while循环的控制条件

Flag变量的初始值为True;并在循环体中,有2个哨兵

第1个哨兵xStr == ‘’来触发FlagFalse;第2个哨兵count > 9来触发FlagFalse

任务二:Flag和哨兵的关系

知识点:使用Flag来控制while循环,本质上,就是根据if语句来检测哨兵,然后触发Flag变量为False

下面这个程序为消息回音,即计算机会将用户输入的字符串,原封不动的输出。这里使用**’quit’**作为哨兵

1
2
3
4
5
6
7
8
9
10
prompt = "输入'quit'结束程序"

Flag = True
while Flag:
message = input(prompt)

if message == 'quit':
Flag = False
else:
print(message)

程序解析:

将变量Flag设置成了True,让程序最初处于活动状态

while循环中,在用户输入后使用一条if语句来检查变量message的值

如果用户输入的是**’quit’,就将变量Flag设置为False,这将导致while**循环不再继续执行

如果用户输入的不是**’quit’**,就将输入作为一条消息打印出来

9.3.4 break和continue控制循环流程

任务一:控制循环流程

知识点:breakcontinue 是专门用于循环流程中断控制的关键字

break:退出循环,不再执行循环的后续代码

continue:不执行本次循环的后续代码,并执行下一轮循环

嵌套循环时,breakcontinue 只针对当前所在循环有效

任务二:break退出循环

在循环过程中,如果某一个条件满足后再希望循环继续执行,可以使用 break退出循环。break 只针对当前所在循环有效

1
2
3
4
5
6
7
8
9
10
11
12
13
14
i = 0

while i < 10:

# break 某一条件满足时,退出循环,不再执行后续重复的代码
# i == 3
if i == 3:
break

print(i)

i += 1

print("over")

知识点:

在循环中,可以使用break语句强制彻底地退出循环,不管循环条件是否满足

如果使用break语句,即使while条件为True,也随时停止循环

break语句也适用于for循环,来退出遍历

下面程序让用户输入一系列去过的城市,并在输入**’quit’后使用break语句立即退出while**循环

1
2
3
4
5
6
7
8
9
10
prompt = "输入喜欢的城市,并以'quit'结束程序"

# 设置条件为永True
while True:
message = input(prompt)

if message == 'quit':
break
else:
print("I'd love to go to " + city.title() + "!")

程序解析:

while条件设置为永真,即如果没有break语句,程序将会无止境的运行

循环体中,要求用户不断输入去过的城市名字,直到输入**’quit’**为止

当用户输入**’quit’后,将执行break**语句来退出循环

任务三:continue跳过该次循环

在循环过程中,如果某一个条件满足后,不希望执行循环代码但是又不希望退出循环,可以使用 continue

知识点:相对于break语句彻底退出循环,continue语句近跳过该次循环,不执行该语句之后的语句,重新返回到循环开头

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
i = 0

while i < 10:
# 当 i == 7 时,不希望执行需要重复执行的代码
if i == 7:
# 在使用 continue 之前,同样应该修改计数器
# 否则会出现死循环
i += 1

continue

# 重复执行的代码
print(i)

i += 1

使用 continue 时,条件处理部分的代码,需要特别注意,不小心会出现 死循环

下面例子中,通过continue语句实现,在循环体中只打印从1到10的奇数

1
2
3
4
5
6
7
current_number = 0
while current_number < 10:
current_number += 1
if current_number % 2 == 0:
continue

print(current_number)

程序解析:

首先将current_number设置成了0,由于它小于10,Python进入while循环

进入循环后,我们以步长1的方式往上数,因此current_number为1

接下来,if语句检查current_number与2的求模运算结果

如果结果为0(意味着current_number可被2整除),就执行continue语句,让Python忽略余下的代码,并返回到循环的开头。如果当前的数字不能被2整除,就执行循环中余下的代码,Python将这个数字打印出来

习题:

7-4 比萨配料:编写一个循环,提示用户输入一系列的比萨配料,并在用户输入**’quit’**时结束循环。每当用户输入一种配料后,都打印一条消息,说我们会在比萨中添加这种配料

1
2
3
4
5
6
7
shuru = "请输入你需要添加的pizza配料:"
shuru +="\n当你输入quit,将停止添加配料:"
pizzas = ""
while pizzas != 'quit':
pizzas = input(shuru)
if pizzas != 'quit':
print("你的比萨添加"+pizzas+"成功\n")
1
2
3
4
5
你的比萨添加牛肉成功

你的比萨添加羊肉成功

你的比萨添加猪肉成功

7-5 电影票:有家电影院根据观众的年龄收取不同的票价:不到3岁的观众免费;3~12岁的观众为10美元;超过12岁的观众为15美元。请编写一个循环,在其中询问用户的年龄,并指出其票价

1
2
3
4
5
6
7
8
while True:
age = int(input("请输入用户年龄:")) # 5
if age < 3:
print("该用户免费")
elif 3 <= age < 12:
print("该年龄段用户收费的是10美元")
else:
print("该年龄段用户收费的是15美元")
1
该年龄段用户收费的是10美元

7-6 三个出口:以另一种方式完成练习7-4或练习7-5,在程序中采取如下所有做法

while循环中使用条件测试来结束循环

使用变量active来控制循环结束的时机

使用break语句在用户输入**’quit’**时退出循环

1
2
3
4
5
6
7
8
9
10
11
active = input("请输入你的年龄:")
while True:
age = int(input("请输入用户年龄:"))
if age < 3:
print("该用户免费")
elif 3 <= age < 12:
print("该年龄段用户收费的是10美元")
else:
print("该年龄段用户收费的是15美元")
if active == "quit":
break

7-7 无限循环:编写一个没完没了的循环,并运行它,并Jupyter通过Kernel–> Interrupt进行重置

1
2
3
4
a = 1
while a >0:
a += 1
print(a)

9.4 嵌套循环

9.4.1 while循环嵌套流程分析

while 嵌套就是:while 里面还有 while

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
while 条件 1:
条件满足时,做的事情1
条件满足时,做的事情2
条件满足时,做的事情3
...(省略)...

while 条件 2:
条件满足时,做的事情1
条件满足时,做的事情2
条件满足时,做的事情3
...(省略)...

处理条件 2

处理条件 1

9.4.2 实例:九九乘法表

任务一:打印小星星

在控制台连续输出五行 *****,每一行星号的数量依次递增:

1
2
3
4
5
*
**
***
****
*****

知识点:

字符串的乘法,表示复制字符串内容

例如,**”“ * 2*,表示复制字符`”*”**两次

使用字符串 ***** 打印

1
2
3
4
5
# 1. 定义一个计数器变量,从数字1开始,循环会比较方便
row = 1
while row <= 5:
print("*" * row)
row += 1

任务二:print 函数的end=””参数

知识点(回顾):

在默认情况下,print 函数输出内容之后,会自动在内容末尾增加换行

如果不希望末尾增加换行,可以通过print 函数的**end=””**关键字参数指定结束字符

end=”@”print 函数输出的尾部添加**@**字符

end=””print 函数输出的尾部不添加任何字符,也不再换行了。

语法格式如下:

1
2
3
4
# 向控制台输出内容结束之后,不会换行
print("*", end="")
# 单纯的换行
print("")

任务三:使用循环嵌套打印小星星

假设Python 没有提供字符串的 ***** 复制操作运算,需要通过嵌套while循环来实现该功能,来实现连续输出五行 *****,每一行星号的数量依次递增

1
2
3
4
5
*
**
***
****
*****

思路分析:

完成 5 行内容的简单输出

分析每行内部的 ***** 应该如何处理?

每行显示的星星和当前所在的行数是一致的

嵌套一个小的循环,专门处理每一行中的星星显示

1
2
3
4
5
6
7
8
9
10
11
row = 1
while row <= 5:
# 假设 python 没有提供字符串 * 操作
# 在循环内部,再增加一个循环,实现每一行的 星星 打印
col = 1
while col <= row:
print("*", end="")
col += 1
# 每一行星号输出完成后,再增加一个换行
print("")
row += 1

任务四:嵌套打印九九乘法表

输出九九乘法表,格式如下:

1
2
3
4
5
1 * 1 = 1
1 * 2 = 22 * 2 = 4
1 * 3 = 32 * 3 = 63 * 3 = 9
1 * 4 = 42 * 4 = 83 * 4 = 12 4 * 4 = 16
...

步骤一:打印 9 行小星星

1
2
3
4
5
6
7
8
9
*
**
***
****
*****
******
*******
********
*********

步骤二:将每一个 ***** 替换成对应的行与列相乘

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 定义起始行
row = 1
# 最大打印 9 行
while row <= 9:
# 定义起始列
col = 1
# 最大打印 row 列
while col <= row:
# end = "",表示输出结束后,不换行
# "\t" 可以在控制台输出一个制表符,协助在输出文本时对齐
# print("%d * %d = %d" % (col, row, row * col), end="\t")
# f-string方式,相对%输出更简洁
print(f"{col} * {row} = {row * col}", end="\t")
# 列数 + 1
col += 1
# 一行打印完成的换行
print("")
# 行数 + 1
row += 1

任务五:字符串中的转义字符(回顾)

\t 在控制台输出一个 制表符,协助在输出文本时 垂直方向 保持对齐。制表符的功能是在不使用表格的情况下在垂直方向按列对齐文本

\n 在控制台输出一个 换行符

转义字符 描述
\ 反斜杠符号
' 单引号
" 双引号
\n 换行
\t 横向制表符
\r 回车

9.4.3 实例:进阶平均数计算

任务一:数据生成

创建一个数据文件,共100行,每行为10~20个随机数,以数字之间**,**为间隔

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import random as rd
# 例如:Data.txt
name = input('请输入文件名: ')
f = open(name, "w+", encoding='utf-8')

for i in range(100):
# 每行元素个数为10~20个
s = rd.randint(10, 20)
for j in range(s):
# 随机生成[-10,10]区间的整数
num = rd.randint(-10, 10)
# 将num转换为字符串,并用','拼接,写入文件中
# 最后一个元素(j=s-1),添加换行符'\n'
if j < s - 1:
f.write(str(num) + ',')
else:
f.write(str(num) + '\n')

print(f'生成结束,请打开{name}查看结果')
f.close()

任务二:字符串拆分

知识点:

语法:str.split(str=””)

描述:通过指定分隔符str对字符串进行切分

参数:str为分隔符,默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等

返回:返回分割后的字符串列表

1
2
3
str = "Line1-abcdef \nLine2-abc \nLine4-abcd"
# 以空格为分隔符,包含 \n
print(str.split());
1
2
3
txt = "Google#Runoob#Taobao#Facebook"
#以#为分隔符
print(txt.split("#"))

任务三:嵌套式循环求平均值

算法分析:

外层循环使用哨兵式循环while循环,for循环会更简单

外层循环:在循环体中,通过readline()按行读取文件。以‘’作为while循环哨兵

内层循环:对每行的字符串使用split()方法进行拆分字符串,返回的是一个子列表,再嵌套for循环,对子列表元素进行计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 输入之前生成数字的文件:Data.txt
fileName = input("输入文件名: ")
infile = open(fileName,'r', encoding='utf-8')

total = 0.0
count = 0

# 从文件中先读一行
line = infile.readline()

# 将line为空作为哨兵,即读到文件末尾
while line != "":
for num in line.split(","):
total += float(num)
count += 1
line = infile.readline()

print("平均值为:", total / count)

嵌套循环的设计准则:

  • 首先设计外层,不考虑内层的内容
  • 然后设计内层,忽略外层循环
  • 最后放在一起,注意保留嵌套循环变量间的耦合性。如果单个循环是正确的,则嵌套的结果就会正常工作,要相信这一点
  • 通过一点练习,将轻松掌握双重甚至三重嵌套循环

9.5 使用while循环来处理列表和字典

任务一:for循环和while循环的不同定位

知识点:

只读模式for循环的目的是通过遍历列表(序列或容器)的每个元素,对它们执行相同的批量化操作。循环体中,对临时变量进行修改,并不会影响原列表元素内容。因此,for循环是一种只读模式

可写模式:如果需要在迭代列表的同时,对元素进行修改,建议使用while循环

任务二:在列表间移动元素

假设有一个列表,其中包含新注册但还未验证的网站用户;验证这些用户后,如何将他们移到另一个已验证用户列表中呢?

使用while循环可以有效的满足上述的需求。在验证用户的同时将其从未验证用户列表中提取出来,再将其加入到另一个已验证用户列表中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 首先,创建一个待验证用户列表
# 和一个用于存储已验证用户的空列表
unconfirmed_users = ['alice', 'brian', 'candace']
confirmed_users = []

# 验证每个用户,直到没有未验证用户为止
# 将每个经过验证的列表都移到已验证用户列表中
while unconfirmed_users:
current_user = unconfirmed_users.pop()

print("待验证用户: " + current_user.title())
confirmed_users.append(current_user)

# 显示所有已验证的用户
print("已验证用户:")
for confirmed_user in confirmed_users:
print(confirmed_user.title())

程序解析:

首先创建了一个未验证用户列表,其中包含用户Alice、Brian和Candace,还创建了一个空列表,用于存储已验证的用户

然后,while循环将不断地运行,直到列表unconfirmed_users变成空的。

在这个循环中,函数pop()以每次一个的方式从列表unconfirmed_users末尾删除未验证的用户

由于Candace位于列表unconfirmed_users末尾,因此其名字将首先被删除、存储到变量current_user中并加入到列表confirmed_users中。接下来是Brian,然后是Alice

为模拟用户验证过程,打印一条验证消息并将用户加入到已验证用户列表中。未验证用户列表会越来越短,而已验证用户列表越来越长。未验证用户列表为空后结束循环,最后打印已验证用户列表

任务三:删除包含特定值的所有列表元素

remove()方法在删除列表特定值时,只能删除列表中,首次出现的元素值。那么如何删除列表中所有等于特定值的元素呢?

假设有一个宠物列表,其中包含多个值为**’cat’的元素。要删除所有‘cat’元素,可以使用while循环,通过in表达式检测列表是否包含‘cat’**来作为循环条件

1
2
3
4
5
6
7
pets = ['dog', 'cat', 'dog', 'goldfish', 'cat', 'rabbit', 'cat']
print(pets)

while 'cat' in pets:
pets.remove('cat')

print(pets)

程序解析:

首先创建了一个列表,其中包含多个值为**’cat’**的元素

打印这个列表后,Python进入while循环,因为它发现**’cat’**在列表中至少出现了一次

进入这个循环后,Python删除第一个**’cat’并返回到while代码行,然后发现‘cat’**还包含在列表中,因此再次进入循环

它不断删除**’cat’**,直到这个值不再包含在列表中,然后退出循环并再次打印列表

任务四:接收用户输入来填充字典

下面来创建一个调查程序,定义responses字典用于存相关问卷信息。核心程序使用带Flag标志变量的while循环。在循环体中,接收用户的问卷信息(用户名和问卷回答),并保存到字典中responses[name] = response

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
responses = {}

# 设置一个Flag标志,指出调查是否继续
Flag = True

while Flag:
# 提示输入被调查者的名字和回答
name = input("\nWhat is your name? ")
response = input("Which mountain would you like to climb someday? ")

# 将答卷存储在字典中
responses[name] = response

# repeat为循环的哨兵
repeat = input("Would you like to let another person respond? (yes/ no) ")
if repeat == 'no':
Flag = False

# 调查结束,显示结果
print("\n--- Poll Results ---")
for name, response in responses.items():
print(name + " would like to climb " + response + ".")

习题:

7-8 熟食店:创建一个名为sandwich_orders的列表,在其中包含各种三明治的名字;再创建一个名为finished_sandwiches的空列表。遍历列表sandwich_orders,对于其中的每种三明治,都打印一条消息,如I made your tuna sandwich,并将其移到列表finished_sandwiches。所有三明治都制作好后,打印一条消息,将这些三明治列出来

1
2
3
4
5
6
7
8
9
sandwich_orders=['Tuna sandwich','Ham cheese sandwich','Chicken sandwich']
finished_sandwiches=[]
while sandwich_orders:
current_orders=sandwich_orders.pop()
print("I made your "+current_orders.title()+".")
finished_sandwiches.append(current_orders)
print("\nAll the sandwiches have been finished.")
for finished_sandwiche in finished_sandwiches:
print(finished_sandwiche.title())
1
2
3
4
5
6
7
8
I made your Chicken Sandwich.
I made your Ham Cheese Sandwich.
I made your Tuna Sandwich.

All the sandwiches have been finished.
Chicken Sandwich
Ham Cheese Sandwich
Tuna Sandwich

7-9 五香烟熏牛肉(pastrami)卖完了:使用为完成练习7-8而创建的列表sandwich_orders,并确保**’pastrami’在其中至少出现了三次。在程序开头附近添加这样的代码:打印一条消息,指出熟食店的五香烟熏牛肉卖完了;再使用一个while循环将列表sandwich_orders中的‘pastrami’都删除。确认最终的列表finished_sandwiches中不包含‘pastrami’**

1
2
3
4
5
6
sandwich_orders = ["a", "b", "pastrami", "c", "pastrami", "d", "pastrami"]
print("五香熏牛肉卖完啦")
while "pastrami" in sandwich_orders:
sandwich_orders.remove("pastrami")
for i in sandwich_orders:
print(i)
1
2
3
4
5
五香熏牛肉卖完啦
a
b
c
d

9.6 习题

  • 猜数字游戏:

    • 系统随机生成一个1~100的数字;
    • 用户共有6次机会猜;
    • 如果用户猜测数字大于系统给出的数字,打印”big”。
    • 如果用户猜测数字小于系统给出的数字,打印”small”。
    • 如果用户猜测的数字等于系统给出的数字,打印”恭喜中奖”,并退出循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import random
x = random.randint(1,100)
print(x)

trycount = 0
while trycount < 6:
tk = int(input('请输入你猜测的数字:'))
if tk == x:
print('恭喜中奖')
break
elif tk < x:
print('too small')
trycount += 1
else:
print('too big')
trycount += 1
else:
print('机会已经用完')
  • 制造星星,根据用户的输入星星行数,分奇数和偶数情况讨论。

    对于偶数,比如输出10行内容,第1行一个星号,第2行2个星号,第5行5个星号和第6行5个星号,第7行4个星号,以此类推第10行1个星号。

    对于奇数,比如输出9行内容,第1行一个星号,第2行2个星号,第5行5个星号,第6行4个星号,以此类推第9行1个星号

1
2
3
4
5
6
n = int(input('num:'))
for i in range(1,2*n,2):
print(('*' * i).center(3 * n))
s = range(1,2*(n-1),2)
for i in s[::-1]:
print(('*' * i).center(3 * n))

计算从1到1000以内所有能同时被3,5和7整除的数的和并输出

1
2
3
4
5
6
list=[]
for i in range(1,1001):
if i%3==0 and i%5==0 and i%7==0:
list.append(i)
a=sum(list)
print(a)
1
4725

计算从1到100临近两个整数的合并依次输出。比如第一次输出3(1+2),第二次输出5(2+3),最后一次输出199(99+100)

1
2
3
4
5
6
s=[]
for i in range(1,101):
if i>=2:
a=i-1+i
s.append(a)
print(s)
1
[3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103, 105, 107, 109, 111, 113, 115, 117, 119, 121, 123, 125, 127, 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199]

一球从100米高度自由落下,每次落地后反跳回原高度的一半,再落下。求它在第n次落地时,共经过多少米?

1
2
3
4
5
6
7
8
9
10
11
12
n = input()  # 5
far = []
high = 100
for i in range(1, int(n)):
if i == 1:
far.append(high)
else:
far.append(high * 2)
high = high / 2

print(f'经过的总距离:far = {sum(far)}')
print(f'第n次反弹多高:high = {high}')
1
2
经过的总距离:far = 275.0
第n次反弹多高:high = 6.25

输出所有的三位水仙花数,其各位数字立方和等于该数本身

1
2
3
4
5
6
for num in range(100, 1000):
x = num // 100
y = num // 10 % 10
z = num % 10
if x ** 3 + y ** 3 + z ** 3 == num:
print(str(num) + "是水仙花")
1
2
3
4
153是水仙花
370是水仙花
371是水仙花
407是水仙花
  • 石头剪刀布,使用while死循环,用户不停输入“石头剪刀布”与计算机对弈,直到quit退出。

    计算机随机生成石头剪刀布。提示,随机生成1~3的整数,来代替 石头:rock;剪刀:scissors;布:paper。

    用户从外部输入对应的字符串,计算机判断,并给结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import random
while True:
print("---石头剪刀布游戏开始---")
print("请按下面提示出拳:石头[1]剪刀[2]布[3]退出[4]")
user=int(input("请输入你的选项:"))
if user==4:
print("游戏退出")
break
computer=random.randint(1,3)
if ((computer==1 and user==3) or (computer==2 and user==1) or (computer==3 and user==2)):
print("玩家出拳为{},电脑出拳为{},玩家胜利".format(user,computer))
elif computer==user:
print("玩家出拳为{},电脑出拳为{},平局".format(user,computer))
else:
print("玩家出拳为{},电脑出拳为{},电脑胜利".format(user,computer))
print("游戏结束")

评论