# 每次循环操作完全相同
# 将“春眠不觉晓”重复3遍
for i in range(3):
print('春眠不觉晓')春眠不觉晓
春眠不觉晓
春眠不觉晓
一些任务需要不断重复相同或相似的动作来完成。 在编程时,可通过循环程序结构来实现这些任务。
上课时,老师通过点名确认学生的出勤情况。对一个班级人数为30人的班级,点名活动进程如下:
……
如何求一个正数x的平方根?可用二分法逐步缩小范围。如求7的平方根:
……
最终区间会变得足够小,区间上的任意点都是 \sqrt{7} 的近似解。
循环程序中,每次循环执行的操作可能完全相同(如打印相同的字符串), 也可能略有差异(如第一次循环打印整数 1,第二次循环打印整数 2)。
循环次数是有限的,否则程序陷入无限循环不会停止。 可以事先固定循环的次数(如循环 3 次就结束),也可设定一个必然能达成的循环停止条件。
# 每次循环操作完全相同
# 将“春眠不觉晓”重复3遍
for i in range(3):
print('春眠不觉晓')春眠不觉晓
春眠不觉晓
春眠不觉晓
# 每次循环操作不完全相同
# 从5开始倒数到1
for i in range(5, 0, -1):
print(i)5
4
3
2
1
for循环用于循环次数确定的情况。
for i in iterable:
循环体iterable是可迭代对象。可以将其理解为一些对象构成的集合。 可迭代对象的具体范围包括:
1. 序列数据类型,如:列表(list),元组(tuple),字符串(str),range;
2. 字典(dict),文件对象(file object);
3. 其他具有`__iter__()`方法的对象。
可用collections.abc中的Iterable结合isinstance()函数,判断对象是否是可迭代对象。
from collections.abc importIterable
isinstance(对象, Iterable) # 判断对象是否是可迭代对象from collections.abc import Iterable
# 列表是可迭代对象
isinstance([1, 2, 3], Iterable)True
你可以自己验证各类型的数据是否是可迭代对象,如'123',123,[1, 2, 3]。
for循环语法如下:
iterable中的下一个对象,将标识符i绑定到此对象;iterable中的项目被耗尽,for循环结束。
__iter__()的对象,对可迭代对象调用__iter__()方法的效果是返回相应的迭代器iterator。__next__()方法。每次调用__next__()方法,返回数据流中的下一个元素;当数据流中的元素消耗殆尽时,__next__()提出一个StopIteration异常。要求迭代器具有方法__iter__()和__next__()的规定,称为迭代器协议(iterator protocol)。for循环前,Python对可迭代对象iterable使用__iter__()方法,获得迭代器。# for循环伪代码
for item in iterable:
循环体# for 循环的实际实现
# 1. 从可迭代对象(iterable)获取迭代器(iterator)
iterator = iter(iterable) # 调用 iterable.__iter__()
while True:
try:
# 2. 从迭代器获取下一个元素
item = next(iterator) # 调用 iterator.__next__()
# 3. 执行循环体
循环体
except StopIteration:
# 4. 捕获StopIteration异常,结束循环
break迭代器协议是Python的核心语言机制,具有为不同数据类型提供统一遍历接口,惰性计算与内存高效,解耦迭代逻辑与数据结构、允许实现更灵活的遍历逻辑等优点。除了for循环,列表推导式,解包,map()、filter()、sum()等内置函数都通过迭代器协议实现,其构成Python迭代功能的基石。
初次接触可迭代对象、迭代器机制,迭代器协议等概念时,会感到比较复杂。 这很正常,因此初学者不用深入理解这些,只要会用for循环就好。 如果有朝一日你成为了重度程序员,应该就能体会迭代器协议的上述优势。
# 将'春眠不觉晓'逐字打印,每个字占一行
for i in '春眠不觉晓':
print(i)春
眠
不
觉
晓
for i in 123:
print(i)--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[5], line 1 ----> 1 for i in 123: 2 print(i) TypeError: 'int' object is not iterable
内置函数range()接受1 \sim 3个位置参数,分别表示起始值,结束值和步长,生成内容为等差数列的可迭代对象。 起始值默认为0,步长默认为1。 注意,range()返回的可迭代对象不含结束值,其最后一个元素恰好在结束值的“前面”。
# 生成从 start 开始,到 stop 结束(不含 stop),公差为 step 的等差数列
# range()函数不接受关键字参数,即传参时直接写数字,不要写`参数名`
# 这里写start, stop, step,只是为了标注参数含义
range(start = 0, stop[, step = 1])# range()接受1个参数
# range(3)的3代表stop结束值
for i in range(3):
print(i)0
1
2
# range()接受2个参数
# range(1, 3)的1代表start起始值,3代表stop结束值
for i in range(1, 3):
print(i)1
2
# range()接受3个参数
for i in range(2, 6, 2):
print(i)2
4
# 步长可以为负
for i in range(6, 2, -2):
print(i)6
4
range对象不存储具体的数,在每次迭代/循环时才计算具体序列值。 因此用print()不能返回range()创建的可迭代对象中的具体成员。要看range()的具体成员,除了用for循环逐个打印,还可以用list()将此对象转换为列表。
# range()对象不存储具体的数
print(range(3))
type(range(3))range(0, 3)
range
# 转换为list后range()的具体成员可以显示
print(list(range(3)))[0, 1, 2]
range对象不存储具体的数,而是随用随取。这种称为惰性计算(lazy evaluation)的特性有什么优势?
range(3.0, 4.0, 0.1)--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[12], line 1 ----> 1 range(3.0, 4.0, 0.1) TypeError: 'float' object cannot be interpreted as an integer
range(start = 10)--------------------------------------------------------------------------- TypeError Traceback (most recent call last) Cell In[13], line 1 ----> 1 range(start = 10) TypeError: range() takes no keyword arguments
range(0, 10, 0)--------------------------------------------------------------------------- ValueError Traceback (most recent call last) Cell In[14], line 1 ----> 1 range(0, 10, 0) ValueError: range() arg 3 must not be zero
用for循环求 1+2+\cdots+100 的值。
total = 0
for i in range(1, 101):
total += i
print(total)5050
有一个数,用3除余2,用5除余3,用7除余2,请问0~1000中这样的数有哪些?
一些数学问题,可以编程用循环枚举求解。这是一种重要的计算思维。
for i in range(1001):
if i % 3 == 2:
if i % 5 == 3:
if i % 7 == 2:
print(i)23
128
233
338
443
548
653
758
863
968
此题也可只使用一个if,自己试试看。
斐波那契数列是每一项等于前两项之和的数列,最初的两项一般 是1、1。显示 Fibonacci 数列:1、1、2、3、5、8、· · · 的前10项。
f1 = 1
f2 = 1
# 因为每轮循环输出2个数,因此5轮循环打印前10项
for i in range(1, 6):
print(f1,f2, end = '\t', sep = '\t')
f1 += f2
f2 += f11 1 2 3 5 8 13 21 34 55
while语句用于无法事先确定循环次数、但知道循环继续条件的情形:当条件满足时,执行循环体,否则脱出循环。
while 条件表达式c:
循环体
用while循环求 1+2+\cdots+100 的值。
i = 1
total = 0
while i <= 100:
total += i
i += 1
print(total)5050
生成 1\sim10 范围内的随机整数,将结果记为x。然后继续生成此范围内的随机数,直到再次生成x。返回迄今为止生成的随机数的个数。
import random
x = random.randrange(1, 11)
counter = 2
while x != random.randrange(1, 11):
counter += 1
print(f'x={x},为了再次得到x,共生成了{counter}个随机数。')x=8,为了再次得到x,共生成了5个随机数。
有的任务需要在循环中再套循环,内层循环要相对外层循环缩进。 如:

# 写一个‘写’字的Python伪代码
for i in range(1, 6):
写第i笔# 写3个‘写’字的Python伪代码
for i in range(3):
# 外层循环
# 开始写第i+1个字
for j in range(1, 6):
# 内层循环
写第i个字的第j笔for i in range(1, 10):
# 外层循环,开始打印第i行
for j in range(1, 10):
# 内层循环,开始打印第i行的第j列
print(i, '*', j, '=', i*j, end = '\t', sep = '')
# 每行打印结束时,打印换行符\n换行
print('\n', end = '')1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
前面演示的是两个for循环的嵌套,实际上根据任务需要,for和while可以自由相互嵌套,嵌套层数可以超过两层。
# 各种嵌套循环
for x in iterable_a:
...
for y in iterable_b:
...
while c1:
...
while c2:
...
for x in iterable_a:
...
while c:
...
while c1:
...
for x in iterable:
...break 打断其所处的循环,接着执行循环语句的后继语句。
continue 跳过本轮循环中 continue 下面尚未执行的语句,进入下一轮循环。
存在嵌套循环时,break,continue 影响的是其所处的循环,注意分辨。
打印九九乘法表,但跳过偶数行。
for i in range(1, 10):
# 外层循环,跳过奇数行
if i % 2 == 0:
# 如果进入此分支
# 这个if所在的循环体本次循环不再执行
# 直接进入下一轮循环
continue
for j in range(1, 10):
# 内层循环,打印第j列
print(i, '*', j, '=', i*j, end = '\t', sep = '')
print('\n', end = '')1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81
对比,如果将上述的continue换为break,得到的输出如下。想想为什么。
for i in range(1, 10):
if i % 2 == 0:
break
for j in range(1, 10):
print(i, '*', j, '=', i*j, end = '\t', sep = '')
print('\n', end = '')1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
打印九九乘法表,但跳过偶数列。
for i in range(1, 10):
# 外层循环,打印第i行
for j in range(1, 10):
# 内层循环,跳过奇数列
if j % 2 == 0:
# 如果进入此分支
# 这个if所在的循环体本次循环不再执行
# 直接进入下一轮循环
continue
print(i, '*', j, '=', i*j, end = '\t', sep = '')
print('\n', end = '')1*1=1 1*3=3 1*5=5 1*7=7 1*9=9
2*1=2 2*3=6 2*5=10 2*7=14 2*9=18
3*1=3 3*3=9 3*5=15 3*7=21 3*9=27
4*1=4 4*3=12 4*5=20 4*7=28 4*9=36
5*1=5 5*3=15 5*5=25 5*7=35 5*9=45
6*1=6 6*3=18 6*5=30 6*7=42 6*9=54
7*1=7 7*3=21 7*5=35 7*7=49 7*9=63
8*1=8 8*3=24 8*5=40 8*7=56 8*9=72
9*1=9 9*3=27 9*5=45 9*7=63 9*9=81
对比,如果将上述的continue换为break,得到的输出如下。想想为什么。
for i in range(1, 10):
for j in range(1, 10):
if j % 2 == 0:
break
print(i, '*', j, '=', i*j, end = '\t', sep = '')
print('\n', end = '')1*1=1
2*1=2
3*1=3
4*1=4
5*1=5
6*1=6
7*1=7
8*1=8
9*1=9
生成1 \sim 10范围内的随机整数,将结果记为x。然后继续生成此范围内的随机数,直到再次生成x。返回迄今为止生成的随机数的个数。使用break。
import random
x = random.randrange(1, 11)
counter = 1
while True:
x1 = random.randrange(1, 11)
counter += 1
if x1 == x:
print(counter)
break 5
用循环判断一个正整数是否是素数。
import math
m = 1001
k = int(math.sqrt(m))
flag = True
i = 2
while (i <= k):
if m % i == 0:
flag = False
break
else:
i += 1
if flag:
print(f'{m}是素数!')
else:
print(f'{m}是合数!具有因子{i}')1001是合数!具有因子7
编程,用二分法求2025的平方根,保留2位小数。
# 二分法查找
x = 2025
tol = 1e-20 # 精确度tolerance
max_iter = 1e10 # 最大迭代次数maximum iteration
n_iter = 1 # 当前迭代次数
e1 = 0 # 区间左端点
e2 = x # 区间右端点
m = (e1 + e2)/2 # 区间中点
while abs(m ** 2 - x) > tol: # 不断近似,直到误差足够小
if n_iter > max_iter:
break
# if语句更新区间端点
if m ** 2 > x:
e2 = m
elif m ** 2 == x:
break
else:
e1 = m
# 更新区间端点后,更新中点
m = (e1 + e2)/2
n_iter += 1
print(f'经过{n_iter}次迭代,得到解{m}。')经过57次迭代,得到解45.0。
编程,用牛顿-拉弗森方法求2025的平方根,保留2位小数。
牛顿-拉弗森方法用利用泰勒展开的前几项求方程 f(x)=0 的根。 对于方程 x^2-a=0 ,具体算法是:
假设t=a,开始循环; 如果t=a/t或小于容差),则t等于a的平方根,循环结束并返回结果; 否则,将t和a/t的平均值赋值给t,继续循环。
a = 2025
tol = 1e-20
max_iter = 1e10
n_iter = 1
t = a
while abs(t - a/t) > tol:
if n_iter > max_iter:
break
t = (a/t + t)/2
n_iter += 1
print(f'经过{n_iter}次迭代,得到解{t}。')经过11次迭代,得到解45.0。
enumerate() 接受可迭代对象作为参数,返回索引与可迭代对象,使用户能在循环中使用索引。 索引默认从 0 开始,可以用 start 参数规定起始索引
seasons = ['Spring', 'Summer', 'Autumn', 'Winter']
for i, s in enumerate(seasons, start = 1):
print(f'第{i}季节:{s}')第1季节:Spring
第2季节:Summer
第3季节:Autumn
第4季节:Winter
zip(iterable1, iterable2, ...)将多个可迭代对象中对应的元素打包成元组,返回这些元组形成的可迭代对象。
如果各可迭代对象参数的元素个数不同,返回与最短参数长度相同的可迭代对象。
a = ['天', '雨', '大陆', '山花', '赤日']
b = ['地', '风', '长空', '海树', '苍穹']
for item in zip(a, b):
print(item)('天', '地')
('雨', '风')
('大陆', '长空')
('山花', '海树')
('赤日', '苍穹')
a = ['天', '雨', '大陆', '山花', '赤日']
b = ['地', '风', '长空', '海树', '苍穹']
for x, y in zip(a,b):
print(f'{x}对{y}')天对地
雨对风
大陆对长空
山花对海树
赤日对苍穹
# zip()多个参数不等长时,返回值与最短参数的长度相同
a = ['天', '雨', '大陆', '山花', '赤日']
b = ['地', '风', '长空']
for x, y in zip(a,b):
print(f'{x}对{y}')天对地
雨对风
大陆对长空
含有break的循环,后面可跟else子句(else的缩进水平与循环的for或while相同):
break 中断的,不执行 else 子句的内容;else子句的内容。for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '=', x, '*', n//x)
break
else: # 这里else与for配对,而非与if配对,代码没错哦
# 如果没能找到n的因子,执行这里
print(n, '是素数。')2 是素数。
3 是素数。
4 = 2 * 2
5 是素数。
6 = 2 * 3
7 是素数。
8 = 2 * 4
9 = 3 * 3
# 不用else的等价代码
is_prime = True
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, '=', x, '*', n//x)
is_prime = False
break
if is_prime:
print(n, '是素数。')
is_prime = True2 是素数。
3 是素数。
4 = 2 * 2
5 是素数。
6 = 2 * 3
7 是素数。
8 = 2 * 4
9 = 3 * 3
猜数字游戏。随机生成一个 0\sim999 范围内的整数,请用户猜测。 对用户的每次猜测,返回“偏大”或“偏小”的反馈,直到用户猜对或认输。 用户认输时,显示正确答案。
1A2B 猜数字:系统随机生成一个指定位数、各位数字都不同的数, 用户每次猜测,系统提示 A 表示数字和位置都正确,B 表示数字正确但位置错误 。 如答案为 1234 ,用户猜测 1356,则系统提示 1A1B 。 根据用户的输入给出提示,直到用户猜对或认输。
“百元买百鸡”是我国古代数学家张丘建在《算经》一书中提出的数学问题:鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。百钱买百鸡,问鸡翁、鸡母、鸡雏各几何? 用现代语言描述为:用100元钱买来100只鸡,公鸡5元钱一只,母鸡3元钱一只,小鸡1元钱3只。请问在这100只鸡中,公鸡、母鸡、小鸡各是多少只?
输出100以内的所有质数。
鸡兔同笼,35头,94足,求鸡、兔的数量。如果无解,则输出“无解”。
赌徒有3元本金。 每次赌博,赌徒有0.5的概率获得1元,有0.5的概率失去1元。 如果赌徒的本金累积到10元,则退出赌博;如果赌博失去所有本金,则破产。进行模拟,报告每局赌博的结果,以及赌徒的结局是见好就收还是破产。