1. 项目概述为什么“循环”是Python编程的基石如果你刚开始学Python可能觉得变量、数据类型、条件判断这些基础概念已经够用了。但当你真正想用代码做点事情比如处理一份几百行的数据、批量重命名一堆文件或者只是想在屏幕上打印一个简单的三角形图案时你会立刻发现没有“循环”你的代码将变得无比冗长和笨拙。循环结构就是那个让你从“手动重复”解放到“自动重复”的关键工具。它允许你告诉计算机“嘿把这个操作重复执行N次或者一直执行直到某个条件满足为止。” 这不仅是编程效率的飞跃更是编程思维的质变。我见过很多新手在条件判断上花了很多时间却对循环一知半解结果写出的代码要么是“复制粘贴”的灾难要么面对稍复杂的任务就束手无策。实际上掌握了循环你才算真正摸到了编程的门槛才能开始处理那些有实际意义的问题。本章的练习题就是帮你把“知道循环”变成“会用循环”最终达到“善用循环”的必经之路。无论你是想用Python做数据分析、自动化办公还是开发小工具循环都是你绕不开的核心技能。2. 循环结构核心概念与语法精讲在深入练习题之前我们必须把Python中两种循环的“里子”和“面子”都搞清楚。这就像学开车你得先明白油门、刹车和方向盘是干什么的而不是直接上路。2.1for循环遍历已知序列的利器for循环的本质是“迭代”。它预设了一个可迭代对象比如列表、字符串、字典的键或者一个数字范围然后依次取出其中的每一个元素执行一遍循环体内的代码。基础语法for 变量 in 可迭代对象: # 循环体执行的操作这里的“变量”会在每次循环时自动被赋值为可迭代对象中的下一个元素。最常见的用法是结合range()函数。range()函数详解这是for循环的最佳拍档用于生成一个整数序列。range(stop): 生成从0到stop-1的整数。例如range(5)生成[0, 1, 2, 3, 4]。range(start, stop): 生成从start到stop-1的整数。例如range(2, 6)生成[2, 3, 4, 5]。range(start, stop, step): 生成从start到stop-1步长为step的整数。例如range(1, 10, 2)生成[1, 3, 5, 7, 9]。注意range()生成的是一个“惰性”的序列对象它并不直接在内存中创建完整的列表而是在循环时按需生成下一个数字。这在处理大范围数字时能显著节省内存。但在Python 2中range()是直接生成列表的这是两个版本的一个重要区别。遍历其他数据结构列表for item in my_list:字符串for char in “hello”:(会依次取出 ‘h’, ‘e’, ‘l’, ‘l’, ‘o’)字典遍历键for key in my_dict:遍历值for value in my_dict.values():遍历键值对for key, value in my_dict.items():2.2while循环基于条件的重复执行while循环不关心序列只关心一个条件。只要条件为True循环就会一直执行下去。它的逻辑更像是“只要…就…”。基础语法while 条件表达式: # 循环体核心要点条件初始化在进入循环前必须确保条件中涉及的变量有初始值。条件更新在循环体内必须有能够改变条件表达式结果的语句否则循环将无限进行下去成为“死循环”。这是while循环最容易出错的地方。适用场景当你不知道需要循环多少次只知道循环结束的条件时while是首选。例如读取用户输入直到输入特定字符或者处理数据直到达到某个阈值。2.3 循环控制语句break,continue,else这三个语句让你能更精细地控制循环的流程。break立即终止整个循环跳出循环体。它像是一个紧急停止按钮。for i in range(10): if i 5: break # 当i等于5时循环立即结束 print(i) # 只会打印 0, 1, 2, 3, 4continue跳过当前循环的剩余语句直接进入下一次循环。它像是“跳过这一轮”的指令。for i in range(5): if i 2: continue # 当i等于2时跳过print语句 print(i) # 会打印 0, 1, 3, 4else这是一个容易被忽略但很有用的语法。当循环正常结束即不是被break语句中断时会执行else块中的代码。for i in range(5): print(i) else: print(“循环正常结束”) # 这行会被执行 for i in range(5): if i 3: break print(i) else: print(“这行不会被执行因为循环被break中断了”)else在搜索场景中特别有用比如在一个列表中查找元素如果没找到循环完整执行完就执行else块中的“未找到”处理逻辑。3. 核心练习题分类解析与实战理解了语法我们就要通过实战来巩固。下面我将练习题分为几大类并给出详细的解题思路和代码实现同时分享我踩过的坑和总结的技巧。3.1 基础打印与数字序列生成这类题目旨在让你熟悉for循环和range()函数的配合。题目示例1使用for循环打印1到100的所有偶数。思路分析偶数就是能被2整除的数。我们可以遍历1到100判断每个数除以2的余数是否为0。更高效的方法是直接利用range()的步长参数从2开始步长为2。代码实现与对比# 方法一使用取余判断通用性强但效率稍低 for i in range(1, 101): # 注意range是右开区间所以要写到101 if i % 2 0: print(i) # 方法二直接生成偶数序列更高效更Pythonic for i in range(2, 101, 2): print(i)实操心得在明确知道序列规律时优先使用range()的步长参数来直接生成目标序列这比在循环体内做条件判断要简洁高效得多。这体现了Python“用语法表达意图”的思想。题目示例2计算123…100的和。思路分析这是一个经典的累加问题。我们需要一个变量比如叫total来保存“当前的和”。在循环开始前它初始化为0。每次循环把当前的数字加到total上。代码实现total 0 # 累加器初始化至关重要 for i in range(1, 101): total total i # 等价于 total i print(f“1到100的和是{total}”) # 输出5050常见错误忘记初始化total或者错误地将total 0放在了循环内部导致每次循环total都被重置为0最终结果错误。3.2 嵌套循环与图形打印嵌套循环一个循环里面包含另一个循环是理解复杂逻辑的关键常用于处理二维数据或打印图形。题目示例3使用嵌套循环打印一个5行5列的星号(*)正方形。思路分析我们可以把图形看成5行。对于每一行我们需要打印5个星号。这正好对应两层循环外层循环控制行数5次内层循环控制每行打印的星号数5次。每打印完一行需要换行。代码实现for i in range(5): # 外层循环控制行i从0到4 for j in range(5): # 内层循环控制列j从0到4 print(‘*’, end‘’) # end‘’ 表示打印后不换行 print() # 内层循环结束打印一个空行即换行输出结果***** ***** ***** ***** *****关键技巧print(‘*’, end‘’)中的end参数。默认情况下print()会在输出末尾添加换行符(\n)。通过设置end‘’我们告诉它用空字符串代替换行符这样星号就能打印在同一行了。内层循环结束后用一个空的print()来产生换行开始新的一行。题目示例4打印一个直角三角形左下角对齐。思路分析第1行有1个星号第2行有2个第i行有i个星号。外层循环i从1到5假设5行内层循环的次数就应该是i次。代码实现for i in range(1, 6): # i代表行号也从1开始 for j in range(i): # 内层循环次数等于行号i print(‘*’, end‘’) print()输出结果* ** *** **** *****3.3 条件交互与while循环应用这类题目强调循环与条件判断的结合以及while循环处理不确定次数任务的能力。题目示例5猜数字游戏。程序随机生成一个1-100之间的数字用户来猜程序根据用户的输入提示“大了”、“小了”或“恭喜猜对”并记录猜的次数。思路分析用random模块生成目标数字。由于猜的次数不确定适合用while循环。循环条件为“猜的数字不等于目标数字”。每次循环内获取用户输入将其转为整数与目标数字比较并给出提示同时猜的次数加1。猜对后用break跳出循环或利用while...else结构。代码实现import random target random.randint(1, 100) # 生成目标数字 count 0 # 计数器初始化 print(“猜数字游戏开始目标在1到100之间。”) while True: # 构造一个“无限循环”靠内部的break来结束 guess int(input(“请输入你猜的数字”)) count 1 # 猜的次数加1 if guess target: print(“猜小了再试试”) elif guess target: print(“猜大了再试试”) else: print(f“恭喜你猜对了你一共猜了{count}次。”) break # 猜对跳出循环避坑指南输入处理input()返回的是字符串必须用int()转换才能比较。如果用户输入的不是数字程序会崩溃。在实际项目中需要用try...except进行异常处理。循环条件这里使用了while True配合break逻辑清晰。也可以使用while guess ! target作为条件但需要在循环外先给guess一个初始值如0并在循环体内最后更新guess结构上稍显别扭。随机数种子random.randint()是基于伪随机数生成器的。在调试时如果希望每次运行结果可复现可以在开头加random.seed(42)42可以是任意整数。3.4 数据处理与逻辑综合这类题目开始模拟真实的数据处理场景需要综合运用循环、条件、变量和数据结构。题目示例6给定一个列表scores [85, 92, 78, 90, 88, 76, 95, 89, 84, 91]请计算平均分、最高分、最低分并统计及格60的人数。思路分析平均分总和除以个数。遍历列表累加求和。最高/最低分定义两个变量max_score和min_score初始值可以设为列表第一个元素。遍历列表如果当前分数比max_score大就更新max_score比min_score小就更新min_score。及格人数定义一个计数器pass_count遍历时判断分数是否60是则计数器加1。代码实现scores [85, 92, 78, 90, 88, 76, 95, 89, 84, 91] total 0 max_score scores[0] # 假设第一个是最高分 min_score scores[0] # 假设第一个是最低分 pass_count 0 for score in scores: # 计算总和 total score # 更新最高分 if score max_score: max_score score # 更新最低分 if score min_score: min_score score # 统计及格人数 if score 60: pass_count 1 average total / len(scores) # 注意确保分母不为零 print(f“平均分{average:.2f}”) # :.2f 表示保留两位小数 print(f“最高分{max_score}”) print(f“最低分{min_score}”) print(f“及格人数{pass_count}”)经验之谈初始化max_score和min_score时一个更稳健的做法是使用float(‘-inf’)负无穷大和float(‘inf’)正无穷大。这样即使列表为空逻辑也是正确的。对于本题用列表第一个元素初始化更直观。另外Python内置函数max(),min(),sum()可以一行代码解决部分问题但练习题的目的正是让我们理解这些函数背后的循环逻辑。4. 进阶技巧与性能考量当你熟练基础循环后需要关注如何写出更高效、更优雅的代码。4.1 列表推导式更优雅的“循环创建列表”列表推导式提供了一种更简洁、更易读的方式来创建列表。它的核心思想是“用一个表达式来定义列表的每个元素并可以附带条件”。传统循环方式创建一个包含1到10所有奇数的平方的列表。squares_of_odds [] for i in range(1, 11): if i % 2 1: squares_of_odds.append(i ** 2)列表推导式squares_of_odds [i ** 2 for i in range(1, 11) if i % 2 1]一行代码完成了循环、条件判断和列表构建。它的结构是[表达式 for 变量 in 可迭代对象 if 条件]。注意事项列表推导式虽然简洁但过度复杂的逻辑比如多层嵌套或复杂的条件会降低可读性。此时传统的for循环可能更合适。记住“可读性”永远比“炫技”更重要。4.2 循环中的常见性能陷阱与优化避免在循环内进行重复计算# 不佳的做法 data [……] # 一个很长的列表 for item in data: result complex_calculation(len(data)) # 每次循环都计算一次len(data) process(item, result) # 优化的做法 data [……] data_length len(data) # 在循环外计算一次 for item in data: result complex_calculation(data_length) process(item, result)len(data)在循环中是不变的提到循环外计算可以节省大量时间。谨慎使用for i in range(len(list)):这种写法通常是为了获取索引i。但更Pythonic的方式是使用enumerate()函数。# 方式一使用索引不够优雅 my_list [‘a’, ‘b’, ‘c’] for i in range(len(my_list)): print(f“索引 {i} 处的元素是 {my_list[i]}”) # 方式二使用enumerate推荐 for index, value in enumerate(my_list): print(f“索引 {index} 处的元素是 {value}”)enumerate()会同时返回索引和元素值代码更清晰。理解循环的“开销”在Python中for循环本身有一定的开销。如果只是对序列中的每个元素进行非常简单的操作比如相加使用内置函数map()、filter()或NumPy等库的向量化操作性能会远超手写循环。但对于初学者先理解并熟练使用循环是第一步。5. 调试与问题排查实战记录即使理解了原理动手写代码时依然会出错。下面是我总结的几个高频错误场景和排查方法。问题1IndentationError: unexpected indent缩进错误这是Python新手最常见的错误。Python用缩进来定义代码块循环体必须比for或while语句多缩进一层通常是4个空格或一个Tab。检查确保循环体内所有语句的缩进量一致。千万不要混用空格和Tab键建议在编辑器中设置“将Tab替换为空格”。示例for i in range(3): print(i) # 错误print语句没有缩进与for不在同一代码块。 print(“Done”) # 错误缩进量不一致。问题2无限循环死循环几乎总是发生在while循环中因为条件永远为True。排查步骤检查条件变量初始化变量在循环开始前是否有合理的值检查条件更新循环体内是否有语句能改变条件变量的值使其最终变为False添加“安全阀”在调试时可以添加一个计数器强制在循环一定次数后退出。count 0 while condition and count 1000: # 安全阀最多循环1000次 # … 循环体逻辑 … count 1 if count 1000: print(“警告可能陷入无限循环”)问题3逻辑错误结果不符合预期循环跑完了但算出来的结果是错的。调试方法使用print()大法在关键位置如循环开始、变量更新后、条件判断前打印变量的值。这是最直接有效的调试手段。total 0 for i in range(5): total i print(f“i{i}, total{total}”) # 查看每次累加的过程 print(f“最终结果{total}”)在纸上模拟执行脑跑代码对于简单的循环拿一张纸列出变量一步步跟着程序逻辑走往往能发现思维盲点。使用调试器如果你使用PyCharm、VSCode等IDE学会使用其内置的调试器可以设置断点、单步执行、查看变量状态是更强大的调试工具。问题4TypeError或ValueError在循环中出现例如试图将字符串与数字相加或者int()转换了一个非数字字符串。预防在处理用户输入或不确定来源的数据前先进行类型检查或异常处理。user_input input(“请输入一个数字”) try: number int(user_input) # 后续使用number的代码 except ValueError: print(“输入的不是有效数字”) # 处理错误情况例如让用户重新输入循环结构是编程中从“顺序执行”到“自动化处理”的关键一跃。我个人的体会是初学阶段不要怕写错多写、多调、多思考。把本章的每一类练习题都亲手敲一遍并尝试自己变通比如把打印星号改成打印数字把累加改成累乘直到你能不假思索地写出正确的循环结构。当你看到几行循环代码就能替代成千上万次手动操作时那种编程带来的成就感会让你对后续更复杂的数据结构、函数和面向对象学习充满动力。最后一个小建议在解决实际问题时先别急着写循环用自然语言把“重复做什么”和“什么时候停止”描述清楚这个思考过程能帮你更快地找到正确的循环实现方式。