资讯动态

Python循环语句练习题:从基础到进阶的边界控制与实战技巧

发布时间:2026/10/15 11:22:26 来源:尧图企业网站定制
循环是Python里最容易被低估的一块内容。刚学完for和while的语法写个1到100求和、打印个九九乘法表感觉已经会了。可真到用的时候——处理一批数据、写个带重试的逻辑、遍历嵌套结构——才发现卡壳的地方全在循环的边界、跳出条件和变量作用域上。这篇内容就是围绕Python循环语句练习题这个主题把我自己带人、自己踩坑过程中反复用到的练习思路和解题细节整理出来。不管你是刚接触Python的新手还是想回头把基础打扎实的开发者下面这些题目的拆解方式、常见错误和优化思路应该都能直接用上。1. 为什么循环练习题不能只刷求和和乘法表1.1 循环的真正难点不在语法在边界控制大部分人练循环第一反应就是写for i in range(1, 101)求和。这类题当然要练但它只训练了循环体怎么写完全没有训练循环什么时候停、什么时候跳、什么时候提前结束。而实际写代码时出问题最多的恰恰是后面这些。举个很典型的例子从列表里找第一个满足条件的元素。新手很容易写成遍历完整个列表再判断而正确做法是找到就break。这两种写法在结果上可能一样但效率差很多而且一旦逻辑复杂起来不break的写法会引入一堆额外的状态变量代码迅速变得难以维护。所以我在设计循环练习题时会有意识地覆盖这几类能力计数与累加最基础训练循环体和累加变量的配合。条件筛选在循环里做判断训练if和循环的嵌套。提前终止用break跳出训练找到就停的思维。跳过当前用continue跳过训练过滤的思维。嵌套循环训练多层遍历和内外层变量的关系。循环与elsePython特有的for...else、while...else训练循环正常结束的判断。边界与死循环训练while的终止条件设计避免死循环。这七类能力基本覆盖了循环在实际项目里90%的使用场景。下面我按这个思路把每一类拆开讲每类给几道有代表性的题重点讲为什么这么写和容易错在哪。1.2 一道题练三遍比三道题各练一遍更有效我观察到一个现象很多人做题是做完就过对了就下一道。但循环这种东西同一道题用不同写法实现一遍收获远大于做三道不同的题。比如求1到100的和这道题至少可以写出四种版本# 版本一最朴素的for循环 total 0 for i in range(1, 101): total i print(total) # 版本二while循环 total 0 i 1 while i 100: total i i 1 print(total) # 版本三用sum和range一行搞定 print(sum(range(1, 101))) # 版本四递归虽然不推荐但能训练思维 def sum_to(n): if n 1: return 1 return n sum_to(n - 1) print(sum_to(100))四种写法背后是四种不同的思维方式。版本一和版本二的区别在于循环变量由谁管理——for由range管理while要自己手动维护i手动维护就容易忘记i 1导致死循环。版本三告诉你Python内置函数能省事但前提是你得知道sum和range的配合。版本四训练的是把循环转成递归的能力虽然Python对递归深度有限制但理解这个转换对后面学算法很有帮助。我的建议是每道基础题至少用for和while各写一遍再想想有没有内置函数或库能一行解决。这个习惯坚持下来你对循环的理解会完全不一样。2. 计数、累加与条件筛选把基础题写出层次2.1 累加题的三个进阶方向求和是最基础的累加题但可以往三个方向进阶。方向一改变累加条件。比如求1到100中所有偶数的和。这时候循环体里要加判断total 0 for i in range(1, 101): if i % 2 0: total i print(total)更优雅的写法是直接让range只产生偶数total sum(range(2, 101, 2)) print(total)range(2, 101, 2)的第三个参数是步长从2开始每次加2直接跳过所有奇数。这个写法比循环里加if更高效因为它减少了循环次数。很多人不知道range有第三个参数或者知道但想不起来用这就是练习的价值——把知道变成条件反射。方向二改变累加对象。比如求一个列表中所有数字的平方和。这时候循环遍历的是列表元素而不是range产生的数字nums [1, 2, 3, 4, 5] total 0 for n in nums: total n ** 2 print(total)这里有个细节for n in nums直接遍历元素比for i in range(len(nums))再nums[i]要清晰得多。新手常犯的错是用索引遍历代码里一堆nums[i]可读性差还容易越界。记住一个原则只需要元素时直接遍历元素需要索引时才用enumerate。方向三累加结果不是数字。比如把列表中所有字符串拼成一个长字符串。这时候累加变量初始值不是0而是空字符串words [Py, thon, , 循, 环] result for w in words: result w print(result)这里有个性能坑字符串在Python里是不可变的每次都会创建新字符串。如果列表很长这种写法效率很低。更好的做法是用.join(words)。但作为练习先用循环写一遍理解累加这个概念可以作用于任何支持的类型然后再学优化写法。2.2 条件筛选在循环里做判断的三种模式条件筛选类题目核心是在循环体里加if。但if放的位置不同效果完全不同。模式一过滤后处理。先判断满足条件才执行累加或其他操作# 统计列表中正数的个数 nums [3, -1, 4, -1, 5, -9, 2] count 0 for n in nums: if n 0: count 1 print(count)模式二分类处理。用if...elif...else在循环里分流# 统计正数、负数、零的个数 nums [3, -1, 4, 0, 5, -9, 0] pos neg zero 0 for n in nums: if n 0: pos 1 elif n 0: neg 1 else: zero 1 print(pos, neg, zero)这里有个小技巧pos neg zero 0这种链式赋值在初始化多个同类型变量时很简洁但要注意它只适合不可变类型数字、字符串、元组。如果写成a b []a和b会指向同一个列表改一个另一个也变这是个经典坑。模式三条件决定是否继续。这个模式用continue实现后面讲跳过时会详细说。条件筛选题最容易错的地方是判断条件的边界。比如统计大于等于60的分数个数有人写成 60有人写成 60一字之差结果完全不同。我的习惯是写完条件后拿边界值手动代入验证一遍。比如列表里有60就看它该不该被算进去然后检查代码是否符合预期。2.3 用表格梳理常见累加/筛选题的解法题目类型循环结构关键点常见错误1到n求和for i in range(1, n1)range右边界不包含写成range(1, n)漏掉n求偶数和range(2, n1, 2)步长参数循环里加if效率低列表元素求和for x in lst直接遍历元素用索引遍历易越界统计满足条件的个数循环if计数变量计数变量初始化为0忘记初始化或初始化位置错分类统计循环if/elif/else互斥条件顺序elif顺序错导致漏统计字符串拼接循环初始值为空串长列表性能差应改用join这张表里的常见错误一栏每一条我都见人犯过。尤其是range的右边界问题Python的range(a, b)是左闭右开包含a不包含b这个设计一开始很反直觉但用多了会发现它和索引、切片保持一致是合理的。记不住的时候就想range(1, 101)产生1到100正好100个数因为101 - 1 100。3. break、continue与循环else控制流的精细操作3.1 break找到就停别做无用功break的作用是立即结束整个循环。最典型的场景是查找在列表里找某个元素找到就停。# 查找目标值返回索引找不到返回-1 nums [4, 7, 2, 9, 5, 1] target 9 index -1 for i, n in enumerate(nums): if n target: index i break print(index) # 3如果不写break循环会继续跑完虽然结果一样但做了无用功。数据量小的时候无所谓数据量大的时候差距明显。更重要的是不break的写法在逻辑复杂时容易出错——比如你找到后还想做点别的操作不break的话后面的元素还会触发同样的操作。break还有一个常见用法是配合while True做无限循环条件退出# 模拟一个输入验证直到输入合法才退出 while True: user_input input(请输入一个正整数: ) if user_input.isdigit() and int(user_input) 0: print(f你输入的是 {user_input}) break print(输入不合法请重试)这种模式在实际项目里非常常见比如重试逻辑、菜单循环、游戏主循环。while True本身是死循环靠内部的break退出。写这种代码时一定要确保每条路径最终都能到达break或return否则就是真死循环。注意break只跳出当前这一层循环。如果有多层嵌套break只结束最内层外层继续。这是新手最容易搞混的点之一。3.2 continue跳过当前继续下一个continue的作用是跳过本次循环剩下的代码直接进入下一次循环。它和break的区别是break是不干了continue是这个不要下一个。# 打印1到10中所有的奇数 for i in range(1, 11): if i % 2 0: continue print(i)这段代码里遇到偶数就continue跳过print所以只打印奇数。等价的写法是把print放进if i % 2 ! 0里两种写法结果一样但思路不同。continue的写法是排除法——先排除不要的剩下的就是要的if包裹的写法是筛选法——直接挑出要的。什么时候用continue更合适当循环体很长而需要跳过的条件在开头时。比如for item in data: if not item: continue # 空数据跳过 if item.type ! target: continue # 类型不对跳过 # 下面是长长的处理逻辑 process(item)这种守卫式写法把各种排除条件集中在开头主逻辑放在后面可读性比层层嵌套的if好很多。这是我个人很推荐的一种风格。continue的一个坑是在while循环里用continue时如果continue跳过了循环变量的更新语句会导致死循环。比如i 0 while i 10: if i 5: continue # 错误i永远等于5死循环 print(i) i 1这段代码在i 5时会无限循环因为continue跳过了i 1。正确做法是把i 1放在continue之前或者改用for循环。这个坑我在实际项目里见过不止一次排查起来还挺费劲因为程序不报错就是卡住不动。3.3 循环else一个被严重低估的特性Python的for和while都可以带else子句这个else在循环正常结束没有被break中断时执行。很多人学Python好几年都不知道这个特性或者知道但不敢用怕别人看不懂。它的典型应用场景是查找未找到处理# 查找目标值找到打印索引找不到打印提示 nums [4, 7, 2, 9, 5, 1] target 8 for i, n in enumerate(nums): if n target: print(f找到了索引是 {i}) break else: print(没找到)如果用传统写法需要额外一个标志变量found False for i, n in enumerate(nums): if n target: print(f找到了索引是 {i}) found True break if not found: print(没找到)对比一下for...else省掉了标志变量逻辑更紧凑。但它的可读性确实有争议——else这个词在这里的含义是没有break而不是否则容易让人误解。我的建议是自己写代码时可以用但团队协作时要看团队规范读别人代码时要知道这个特性别看到else就以为是条件分支。while...else的用法类似但更少见。一个典型场景是重试N次都失败则报错attempts 3 while attempts 0: result try_operation() if result success: print(操作成功) break attempts - 1 else: print(重试3次都失败了)这里else在while条件变为False即attempts减到0时执行表示循环跑完了都没成功。3.4 break/continue/else的对比与选择关键字作用执行时机典型场景break立即结束整个循环满足某条件时查找命中、输入合法、重试成功continue跳过本次剩余代码满足某条件时过滤无效数据、守卫式写法else循环正常结束后执行循环未被break中断查找未命中、重试全失败选择的原则很简单要停止整个循环用break要跳过当前用continue要处理循环跑完但没触发break用else。三者可以组合使用但组合太多会降低可读性这时候宁可多写几行代码换清晰。4. 嵌套循环从打印图形到处理二维数据4.1 嵌套循环的执行顺序外层走一步内层走一圈嵌套循环是循环练习里最容易绕晕的部分。核心要记住一句话外层循环每执行一次内层循环完整执行一遍。for i in range(1, 4): for j in range(1, 4): print(fi{i}, j{j})输出是i1, j1 i1, j2 i1, j3 i2, j1 i2, j2 i2, j3 i3, j1 i3, j2 i3, j3可以看到i1时j从1跑到3然后i2j又从1跑到3。总共执行3×39次。理解了这个顺序打印各种图形就顺理成章了。4.2 打印图形的通用思路把图形翻译成行列关系打印图形题的本质是找出每一行打印什么以及行数和列数的关系。直角三角形# 打印5行第i行打印i个星号 for i in range(1, 6): print(* * i)输出* ** *** **** *****这里其实只用了一层循环因为* * i直接生成了i个星号。如果非要用嵌套循环for i in range(1, 6): for j in range(i): print(*, end) print() # 换行内层range(i)产生0到i-1共i次每次打印一个星号不换行内层结束后print()换行。这个写法虽然啰嗦但训练的是内层控制列的思维。等腰三角形# 打印5行等腰三角形 n 5 for i in range(1, n 1): spaces * (n - i) stars * * (2 * i - 1) print(spaces stars)输出* *** ***** ******* *********这道题的关键是找出空格数和星号数与行号i的关系第i行有n - i个空格有2 * i - 1个星号。这个关系不是猜出来的是数出来的——拿n5第1行4个空格1个星号第2行3个空格3个星号第3行2个空格5个星号规律一目了然。九九乘法表for i in range(1, 10): for j in range(1, i 1): print(f{j}*{i}{i*j}, end\t) print()输出1*11 1*22 2*24 1*33 2*36 3*39 ...这里内层range(1, i 1)保证第i行打印i个式子end\t用制表符分隔内层结束后换行。九九乘法表是嵌套循环的经典题因为它同时训练了内层次数依赖外层变量和格式化输出两个能力。4.3 嵌套循环处理二维数据除了打印图形嵌套循环更实用的场景是处理二维数据比如矩阵。# 矩阵转置 matrix [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] transposed [] for j in range(len(matrix[0])): row [] for i in range(len(matrix)): row.append(matrix[i][j]) transposed.append(row) print(transposed) # [[1, 4, 7], [2, 5, 8], [3, 6, 9]]这段代码的逻辑是外层遍历列索引j内层遍历行索引i把matrix[i][j]收集成新的一行。注意外层是len(matrix[0])列数内层是len(matrix)行数这个顺序和直觉相反容易写错。写的时候先想清楚新矩阵的每一行对应原矩阵的每一列就不容易搞混。Python里矩阵转置其实有更简单的写法list(zip(*matrix))。但作为练习先用嵌套循环写一遍理解转置的本质再学这种一行流写法收获更大。嵌套循环的性能问题也值得提一句。如果外层和内层都是遍历大数据集总次数是两者相乘很容易爆炸。比如两个各1000元素的列表做笛卡尔积就是100万次操作。实际项目里遇到嵌套循环要想想能不能用字典、集合或itertools优化。比如找两个列表中相同的元素用嵌套循环是O(n²)用集合交集是O(n)a [1, 2, 3, 4, 5] b [4, 5, 6, 7, 8] # 嵌套循环写法 common [] for x in a: for y in b: if x y: common.append(x) # 集合写法 common list(set(a) set(b))两种写法结果一样但集合写法快得多。练习时两种都写理解差异实际用的时候选高效的。5. while循环的终止条件与死循环排查5.1 while和for的选择知道次数用for不知道次数用whilefor循环适合遍历一个已知序列或重复固定次数while循环适合重复直到某个条件满足。判断标准很简单如果你能提前说出循环要跑多少次用for如果只能说出跑到什么时候停用while。# 已知次数用for for i in range(10): print(i) # 未知次数用while total 0 n 1 while total 100: total n n 1 print(n) # 找到累加到超过100需要多少个数第二段代码里你不知道要加多少个数才能超过100所以用while。这种条件驱动的循环是while的主场。5.2 死循环的三种典型成因死循环是while最常见的坑。程序不报错就是卡住不动CPU跑满。三种典型成因成因一忘记更新循环变量。i 0 while i 10: print(i) # 忘记写 i 1i永远是0条件永远为真。这是最经典的死循环。成因二更新语句写错方向。i 10 while i 0: print(i) i 1 # 应该是 i - 1i越来越大永远大于0。成因三条件永远为真。while True: print(hello) # 没有breakwhile True本身没问题但必须有break或return退出。写while True时我习惯先把退出条件写好再写循环体避免忘记。排查死循环的方法在循环体里加一句print打印循环变量跑一下看变量有没有按预期变化。如果变量不变或变化方向不对就是死循环。更专业的做法是用调试器打断点单步执行看变量。但初学阶段print大法足够用。5.3 while循环的实战模式模式一累加到阈值。# 累加自然数直到和超过1000 total 0 n 0 while total 1000: n 1 total n print(f加到{n}时和超过1000和为{total})模式二数字处理。# 反转一个整数 num 12345 reversed_num 0 while num 0: reversed_num reversed_num * 10 num % 10 num // 10 print(reversed_num) # 54321这道题很经典训练的是用取余和整除逐位处理数字。num % 10取最后一位num // 10去掉最后一位循环直到num为0。每一步的逻辑要能说清楚不然容易写错。模式三输入验证。while True: age input(请输入年龄: ) if age.isdigit() and 0 int(age) 150: print(f年龄是 {age}) break print(输入不合法请重新输入)这种模式在实际项目里到处都是核心是循环校验break。模式四模拟过程。# 模拟一个球从100米落下每次弹起高度为上次的一半求第10次弹起高度 height 100 for i in range(10): height / 2 print(height)这道题其实用for更合适因为次数已知。但如果问弹起到高度小于1米需要多少次就得用whileheight 100 count 0 while height 1: height / 2 count 1 print(count)选择for还是while就看次数是否已知。5.4 while循环的常见错误对照表错误现象可能原因排查方法修复方式程序卡住不输出死循环加print看变量检查变量更新和条件循环次数不对边界条件错手动代入边界值调整和结果多算/少算一次初始值或更新时机错打印每轮变量调整初始值或更新位置continue导致死循环continue跳过了变量更新检查continue位置把更新移到continue前循环体一次都没执行初始条件就不满足检查初始值调整初始值或条件这张表里的每一条都是我在实际写代码和帮人排查时反复遇到的。尤其是结果多算/少算一次几乎每个人都犯过。解决办法就是拿最小案例手动跑一遍比如循环3次的情况一步步看变量怎么变。6. 循环练习的进阶方向与实战建议6.1 从循环到推导式什么时候该换写法Python的列表推导式、字典推导式、生成器表达式本质上都是循环的语法糖。练完基础循环后应该逐步学会在合适场景下用推导式替代循环。# 循环写法 squares [] for i in range(1, 11): squares.append(i ** 2) # 推导式写法 squares [i ** 2 for i in range(1, 11)]推导式更简洁但不是什么情况都适合。我的判断标准是如果循环体只有遍历简单变换收集三步用推导式如果循环体里有复杂逻辑、多个分支、或者副作用操作如打印、写文件用普通循环。带条件的推导式# 1到20中所有偶数的平方 evens_squared [i ** 2 for i in range(1, 21) if i % 2 0]嵌套推导式对应嵌套循环# 生成乘法表的所有式子 table [f{j}*{i}{i*j} for i in range(1, 10) for j in range(1, i 1)]注意嵌套推导式的顺序for i在前for j在后和嵌套循环的书写顺序一致。这个顺序容易搞反记不住就想想等价的循环写法。6.2 用循环解决实际小问题练习题做多了可以尝试用循环解决一些实际小问题这样能真正体会到循环的用处。问题一统计一段文本中每个字符出现的次数。text hello world count {} for ch in text: if ch in count: count[ch] 1 else: count[ch] 1 print(count)更简洁的写法用dict.getcount {} for ch in text: count[ch] count.get(ch, 0) 1count.get(ch, 0)的意思是取ch的值没有就返回0这样就不用写if...else了。这个技巧在实际项目里非常常用。问题二找出列表中出现次数最多的元素。nums [1, 3, 2, 3, 5, 3, 2, 1, 3] count {} for n in nums: count[n] count.get(n, 0) 1 max_count 0 max_num None for n, c in count.items(): if c max_count: max_count c max_num n print(max_num, max_count)这段代码用了两个循环第一个统计次数第二个找最大值。第二个循环也可以用内置函数max(count, keycount.get)一行搞定但作为练习先手写一遍理解逻辑。问题三判断一个数是不是质数。def is_prime(n): if n 2: return False for i in range(2, int(n ** 0.5) 1): if n % i 0: return False return True这道题的关键是循环范围到sqrt(n)就够了因为如果n有大于sqrt(n)的因子必然有小于sqrt(n)的对应因子。这个优化能把复杂度从O(n)降到O(√n)。int(n ** 0.5) 1里的1是为了包含sqrt(n)本身因为range右边界不包含。6.3 循环练习的节奏建议最后说说练习节奏。我的建议是分三阶段第一阶段单知识点练习。每学一个循环特性for、while、break、continue、else、嵌套就集中做5到10道针对这个特性的题。这个阶段追求会用不追求快。第二阶段混合练习。把多个特性混在一起做题比如用循环条件break实现一个查找功能。这个阶段追求用对即知道什么场景用什么特性。第三阶段项目练习。用循环解决实际小问题比如统计文本、处理数据、实现小游戏逻辑。这个阶段追求用好即写出可读、高效、健壮的代码。每个阶段不用严格分开可以交叉进行。但有一点很重要每道题做完后回头看看有没有更简洁或更高效的写法。这个回头看的习惯是区分会写和写好的关键。提示练习时不要怕写错。循环的边界问题、死循环问题只有自己踩过才能真正记住。看别人代码觉得懂了和自己动手写对中间差着十万八千里。我在带人的过程中发现循环这块内容光看是看不会的必须动手写、动手调、动手改。上面这些题目和思路建议你挑几道自己敲一遍尤其是那些常见错误的部分故意写错一次看看报什么错、卡在哪里比直接写对印象深得多。循环是后面学函数、类、算法的基础这块打扎实了后面的路会顺很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑