跳到主要内容

循环

循环让程序重复执行一段代码:遍历课程列表、累计订单金额、不断读取用户输入,都是循环的典型场景。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)}")

先把每个元素分类,再统计结果,是循环处理数据的常见模式。

练习​

  1. 使用 for 计算 1 到 100 的和以及所有偶数的和。
  2. 使用 while 实现一个最多猜 5 次的数字猜谜程序。
  3. 使用 enumerate() 找出成绩列表中第一个不及格成绩的位置。
  4. 使用 zip() 将商品名称、价格和数量组合起来,计算总金额。
  5. 编写质数判断函数,使用 for ... else 表示“没有找到因数”。

小结​

  • for 适合遍历可迭代对象,while 适合“条件满足就继续”的场景。
  • range() 生成整数范围,enumerate() 获取索引,zip() 并行遍历。
  • break 结束循环,continue 跳过本轮;循环 else 只在未触发 break 时执行。
  • 不要直接修改正在遍历的列表;推导式通常更简洁安全。
  • 生成器表达式按需产生数据,适合大规模计算。