# 第 1-6 课:循环 ## 一、本课目标 完成本课后,你应该能够: 1. 解释循环为什么能减少重复代码; 2. 使用 `for` 循环按照指定次数重复执行代码; 3. 使用 `range()` 生成整数序列; 4. 使用 `while` 在条件成立期间重复执行; 5. 使用计数器记录执行次数; 6. 使用累加器汇总一组数据; 7. 在循环中结合 `if` 进行判断; 8. 使用 `break` 提前结束循环; 9. 使用 `continue` 跳过本次循环; 10. 识别并避免常见的死循环。 ## 二、前置知识 开始本课前,你应该已经掌握: - 变量与基础数据类型; - 数字计算和比较运算; - `if...elif...else` 条件判断; - `input()` 和类型转换; - 代码块需要使用四个空格缩进。 ## 三、为什么需要循环 如果要输出五次学习提醒,可以重复写五行: ```python print("开始学习 Python") print("开始学习 Python") print("开始学习 Python") print("开始学习 Python") print("开始学习 Python") ``` 这种写法存在明显问题: - 重复代码很多; - 修改文字时要修改多个位置; - 执行次数较大时无法手工编写; - 容易漏写或写错。 循环(Loop)可以让一段代码重复执行: ```python for count in range(5): print("开始学习 Python") ``` 循环的核心思想是:让计算机负责重复,人只需要描述重复规则。 ## 四、`for` 循环 `for` 循环适合处理“已经知道重复次数”或“依次处理一组数据”的场景。 基本结构: ```python for 循环变量 in 可迭代对象: 重复执行的代码 ``` 第一次接触“可迭代对象”时,可以先把它理解为能够依次提供数据的对象。字符串、列表和 `range()` 都可以依次提供数据。 示例: ```python for count in range(3): print("正在进行 Agent 学习打卡") ``` 输出三次相同内容。 每次循环时,`range(3)` 会依次提供一个整数,并临时保存到循环变量 `count` 中。 ## 五、认识 `range()` `range()` 用于表示一个整数范围,经常与 `for` 配合。 ### 5.1 `range(结束值)` ```python for number in range(5): print(number) ``` 输出: ```text 0 1 2 3 4 ``` 关键规则:从 `0` 开始,包含开始值,不包含结束值。 因此 `range(5)` 提供 5 个整数,但最后一个整数是 `4`。这种“不包含结束值”的规则在 Python 中非常常见。 ### 5.2 `range(开始值, 结束值)` ```python for day in range(1, 6): print(day) ``` 输出 `1` 到 `5`。`6` 仍然不包含在范围中。 如果希望显示“第 1 次”到“第 5 次”,`range(1, 6)` 通常比 `range(5)` 更直观。 ### 5.3 `range(开始值, 结束值, 步长)` 步长表示每次增加多少: ```python for number in range(0, 11, 2): print(number) ``` 输出: ```text 0 2 4 6 8 10 ``` 步长也可以是负数: ```python for number in range(5, 0, -1): print(number) ``` 输出从 `5` 到 `1`,可用于倒计时。 ## 六、使用循环变量 循环变量会在每次循环时保存当前数据: ```python for day in range(1, 4): print(f"第 {day} 天:完成 Python 学习") ``` 输出: ```text 第 1 天:完成 Python 学习 第 2 天:完成 Python 学习 第 3 天:完成 Python 学习 ``` 循环变量应使用有意义的名称,例如 `day`、`task_number`,避免长期使用难以理解的 `a`、`x`。 ## 七、遍历字符串 `for` 也能依次取得字符串中的每个字符: ```python for character in "Agent": print(character) ``` 输出: ```text A g e n t ``` 这种“从头到尾依次取出数据”的操作称为遍历(Traversal)。以后学习列表、字典和文件时,会经常使用遍历。 ## 八、计数器 计数器(Counter)是用来记录次数的变量。 ```python completed_count = 0 for task_number in range(1, 6): completed_count += 1 print(f"已完成 {completed_count} 个任务") ``` 执行过程: 1. 循环前把计数器初始化为 `0`; 2. 每次循环执行 `completed_count += 1`; 3. 循环五次后,计数器变为 `5`。 初始化必须写在循环外。如果写在循环内,每次都会重新变回 `0`。 ## 九、累加器 累加器(Accumulator)用于把多次产生的数值汇总起来。 ```python total_hours = 0.0 for day in range(1, 6): daily_hours = float(input(f"请输入第 {day} 天的学习小时数:")) total_hours += daily_hours print(f"总学习时间:{total_hours} 小时") ``` `total_hours` 的变化过程可能是: ```text 初始值:0.0 第 1 天后:2.0 第 2 天后:3.5 第 3 天后:6.0 ``` 计数器通常每次增加固定值;累加器通常加入每次得到的实际数据。 ## 十、循环与条件判断结合 循环中可以使用 `if`: ```python passed_count = 0 for score in range(55, 101, 15): if score >= 60: passed_count += 1 print(f"{score} 分:通过") else: print(f"{score} 分:未通过") print(f"通过数量:{passed_count}") ``` 注意缩进层级: - `for` 内部缩进一级; - `if` 内部再缩进一级; - 回到循环外时取消全部循环缩进。 ## 十一、`while` 循环 `while` 的中文含义是“当……时”。只要条件为 `True`,循环就会继续。 基本结构: ```python while 条件: 重复执行的代码 ``` 示例: ```python current_day = 1 while current_day <= 3: print(f"完成第 {current_day} 天学习") current_day += 1 ``` 执行过程: 1. `current_day` 初始为 `1`; 2. 判断 `current_day <= 3`,成立则执行循环; 3. 输出后把 `current_day` 增加 `1`; 4. 回到条件处重新判断; 5. 当 `current_day` 变为 `4` 时,条件为 `False`,循环结束。 ## 十二、`for` 和 `while` 如何选择 通常可以这样判断: - 已知需要重复多少次:优先考虑 `for`; - 不知道次数,只知道结束条件:优先考虑 `while`。 示例场景: ```text 依次处理 7 天学习记录 → for 重复询问密码直到输入正确 → while 输出 1 到 100 → for 余额大于 0 时继续扣费 → while ``` 两者有时可以互相改写,但应选择更能表达业务意图的方式。 ## 十三、避免死循环 死循环(Infinite Loop)是无法自然结束的循环。 错误示例: ```text current_day = 1 while current_day <= 3: print(current_day) ``` 循环中没有修改 `current_day`,条件会一直为 `True`,程序不断输出 `1`。 编写 `while` 时必须检查: 1. 条件中的变量是否会发生变化; 2. 变化方向是否会逐渐接近结束条件; 3. 是否存在明确的退出方式。 如果程序意外进入死循环,可以在终端中按 `Ctrl + C` 尝试停止。 ## 十四、使用 `break` 提前结束循环 `break` 表示立即结束当前循环: ```python while True: command = input("请输入命令,输入 exit 结束:") if command == "exit": break print(f"正在处理命令:{command}") print("程序已结束") ``` `while True` 本身会无限循环,但遇到 `break` 后可以退出。只有存在清晰退出条件时,才应使用这种结构。 `break` 只结束它所在的最近一层循环,不会直接结束整个 Python 程序。 ## 十五、使用 `continue` 跳过本次循环 `continue` 表示跳过本次循环剩余代码,直接开始下一次循环: ```python for day in range(1, 6): if day == 3: continue print(f"记录第 {day} 天学习数据") ``` 第 3 天不会输出,其他天正常输出。 可以把两者简单区分为: - `break`:整个循环到此结束; - `continue`:只跳过当前这一次,循环还会继续。 ## 十六、嵌套循环初步认识 循环内部还可以包含循环: ```python for week in range(1, 3): for day in range(1, 4): print(f"第 {week} 周,第 {day} 天") ``` 外层循环每执行一次,内层循环都会完整执行三次,因此一共输出 `2 × 3 = 6` 行。 嵌套循环容易增加理解和运行成本。本课只要求看懂简单结构,练习不强制使用。 ## 十七、运行本课示例 在 PowerShell 中执行: ```powershell cd D:\Code\Python\01_python基础\1_6_循环 python loops.py ``` 示例会演示: - `range()` 的三种常见形式; - 计数和累加; - 循环结合条件判断; - `while` 的变量更新; - `break` 和 `continue`。 示例不需要用户输入,可以直接运行并对照注释观察结果。 ## 十八、常见错误 ### 18.1 忘记冒号 `for` 和 `while` 行末都必须使用英文冒号 `:`。 ### 18.2 循环体没有缩进 属于循环的代码必须统一缩进四个空格。 ### 18.3 `range()` 结束值理解错误 `range(1, 5)` 提供 `1、2、3、4`,不包含 `5`。 ### 18.4 把计数器初始化写在循环内 这样每次循环都会重置,无法正确累计。 ### 18.5 `while` 忘记更新条件变量 这很可能造成死循环。 ### 18.6 混淆 `break` 与 `continue` `break` 结束循环,`continue` 只跳过当前一次。 ### 18.7 循环变量命名没有含义 优先使用 `day`、`task_number` 等名称,帮助读者理解当前遍历的数据。 ## 十九、课堂练习 打开 `practice.py`,完成“Agent 学习打卡统计器”。程序需要收集连续多天的学习时长,统计总时长、有效学习天数和达标情况。 运行命令: ```powershell python practice.py ``` 建议先使用以下数据测试: ```text 计划打卡天数:5 第 1 天:2 第 2 天:0 第 3 天:1.5 第 4 天:-1 第 5 天:3 ``` 约定: - `-1` 表示本次数据无效,使用 `continue` 跳过; - `0` 是有效记录,但不算完成学习; - 大于 `0` 算一个有效学习日; - 累计学习时长达到 `5` 小时视为总目标达标。 使用上述数据时,预期总时长为 `6.5` 小时,有效学习日为 `3` 天,无效记录为 `1` 条,总目标达标。 ## 二十、思考题 1. `range(5)` 会提供哪些整数? 2. 为什么 `range(1, 6)` 可以表示第 1 到第 5 次? 3. 计数器与累加器有什么区别? 4. 哪些场景更适合使用 `while`? 5. `break` 和 `continue` 有什么区别? 6. `while` 循环为什么容易出现死循环? 7. 循环中的 `if` 为什么通常会比循环多一级缩进? ## 二十一、本课小结 - 循环用于重复执行代码; - `for` 适合已知次数或依次处理数据的场景; - `range()` 包含开始值,不包含结束值; - 计数器记录次数,累加器汇总数值; - `while` 在条件为真时持续执行; - `while` 中必须确保条件最终能够变为假; - `break` 提前结束循环; - `continue` 跳过当前一次循环; - 循环可以与条件判断结合,实现更真实的业务逻辑。 ## 二十二、验收标准 - [ ] 能使用 `for` 和 `range()` 重复执行代码; - [ ] 能解释 `range()` 为什么不包含结束值; - [ ] 能使用计数器和累加器; - [ ] 能在循环中使用条件判断; - [ ] 能编写可以正常结束的 `while` 循环; - [ ] 能区分 `break` 和 `continue`; - [ ] 能完成并运行 `practice.py`; - [ ] 能使用建议数据得到正确统计结果; - [ ] 能回答七道思考题。