循环
循环让程序重复执行一段代码:遍历课程列表、累计订单金额、不断读取用户输入,都是循环的典型场景。Python 主要提供 for 和 while 两种循环。
for:遍历可迭代对象
for 逐个取出可迭代对象中的元素:
languages = ["Python", "Go", "Dart"]
for language in languages:
print(language)
列表、元组、字符串、字典、集合、文件和生成器都可以被遍历。循环变量在每轮开始时绑定当前元素:
for character in "Hi":
print(character)
range() 生成整数序列
range() 常用于重复指定次数:
for number in range(5):
print(number) # 0 到 4
它支持 range(stop)、range(start, stop) 和 range(start, stop, step):
print(list(range(2, 8))) # [2, 3, 4, 5, 6, 7]
print(list(range(10, 0, -2))) # [10, 8, 6, 4, 2]
stop 永远不包含在结果中,步长不能为零。range 是惰性的范围对象,不会一次性创建全部整数列表,适合大范围循环。
获取索引:enumerate()
需要同时获得位置和元素时使用 enumerate():
tasks = ["阅读", "练习", "复习"]
for index, task in enumerate(tasks, start=1):
print(f"{index}. {task}")
这比 for index in range(len(tasks)) 更易读,也避免手动处理索引。
并行遍历:zip()
names = ["小林", "小周"]
scores = [88, 95]
for name, score in zip(names, scores):
print(f"{name}:{score}")
zip() 默认在最短序列结束时停止。Python 3.10+ 可以使用 strict=True,在长度不一致时立即报错:
for name, score in zip(names, scores, strict=True):
print(name, score)
while:条件满足时重复
while 在每轮开始前判断条件,为真则执行循环体:
count = 3
while count > 0:
print(count)
count -= 1
print("开始")
循环体必须让条件最终变为假,否则会形成死循环。常见做法是更新计数器,或在满足业务条件时 break。
输入校验循环
while True:
answer = input("请输入 yes 或 no:").strip().lower()
if answer in {"yes", "no"}:
break
print("输入无效,请重试")
print(f"你的选择是 {answer}")
while True 本身不会结束,必须确保所有路径最终执行 break 或抛出异常。
break 和 continue
break 立即结束当前循环,continue 跳过本轮剩余代码并进入下一轮:
for number in range(1, 10):
if number == 7:
break
if number % 2 == 0:
continue
print(number) # 只输出 1、3、5
嵌套循环中,break 只影响所在的最内层循环。需要同时退出多层循环时,可以使用标志变量、提取函数并 return,或重新组织数据处理逻辑。
循环的 else
循环可以带 else。当循环自然结束(没有执行 break)时,才执行 else:
target = 7
for number in range(2, target):
if target % number == 0:
print("不是质数")
break
else:
print("是质数")
while 也支持 else。如果通过 break 离开循环,else 会被跳过。这个特性适合表达“遍历寻找目标,找不到时执行备用逻辑”。
嵌套循环
嵌套循环用于遍历二维数据:
matrix = [[1, 2], [3, 4]]
for row in matrix:
for value in row:
print(value)
嵌套层数越多,时间复杂度通常越高,也越难阅读。可以考虑使用 itertools、字典索引或拆分函数来简化。
修改正在遍历的列表
不要在遍历列表时直接删除元素,否则索引移动可能导致元素被跳过:
numbers = [1, 2, 3, 4, 5]
numbers = [number for number in numbers if number % 2 == 1]
print(numbers) # [1, 3, 5]
如果确实需要原地删除,可以遍历副本:
numbers = [1, 2, 3, 4]
for number in numbers[:]:
if number % 2 == 0:
numbers.remove(number)
推导式和生成器表达式
简单的循环生成可以写成列表推导式:
squares = [number * number for number in range(1, 6)]
只需逐个消费结果、无需立即保存整个列表时,可以使用生成器表达式:
total = sum(number * number for number in range(1_000_000))
生成器按需产生值,节省内存;但结果只能顺序消费一次。
循环中的异常处理
读取多条外部数据时,可以在循环内部处理单条错误,让其他数据继续:
texts = ["10", "oops", "30"]
total = 0
for text in texts:
try:
total += int(text)
except ValueError:
print(f"跳过无效数据:{text}")
print(total) # 40
不要用宽泛的 except Exception 隐藏所有错误,应捕获预期的异常类型。
常见错误
range(1, 5)只包含 1 到 4,忘记“右边界不包含”会导致少循环一次。while循环忘记更新控制变量会一直运行;调试时可以打印变量或设置最大尝试次数。continue会跳过本轮后续代码,资源释放、计数和日志应放在不会被意外跳过的位置。- 遍历字典时不要依赖“修改字典大小”的行为;需要删除时先收集键,再统一处理。
综合示例:统计成绩
scores = [88, 59, 76, 92, 45]
passed = []
failed = []
for score in scores:
if score >= 60:
passed.append(score)
else:
failed.append(score)
print(f"及格人数:{len(passed)}")
print(f"不及格人数:{len(failed)}")
先把每个元素分类,再统计结果,是循环处理数据的常见模式。
练习
- 使用
for计算 1 到 100 的和以及所有偶数的和。 - 使用
while实现一个最多猜 5 次的数字猜谜程序。 - 使用
enumerate()找出成绩列表中第一个不及格成绩的位置。 - 使用
zip()将商品名称、价格和数量组合起来,计算总金额。 - 编写质数判断函数,使用
for ... else表示“没有找到因数”。
小结
for适合遍历可迭代对象,while适合“条件满足就继续”的场景。range()生成整数范围,enumerate()获取索引,zip()并行遍历。break结束循环,continue跳过本轮;循环else只在未触发break时执行。- 不要直接修改正在遍历的列表;推导式通常更简洁安全。
- 生成器表达式按需产生数据,适合大规模计算。