资讯详情

Python入门第六课:for循环、range()与数字列表实战

📅 2026/11/3 7:18:44 | 华诺云谱 👁 阅读
Python入门第六课:for循环、range()与数字列表实战
1. 第六课为什么把 for 循环单独拎出来讲带入门班带到第六课几乎每期都会遇到同一个分水岭前五节课学员写的代码行数基本等于手工劳动量三个数排序写三行比较五个成绩求平均写五行赋值求和。到了第六课变量、列表、条件判断都认得全了此时如果还不给 for 循环学员面对“求 1 到 100 的和”这种题就只能硬算或者干脆复制粘贴一百行。for 循环和数字列表这一课本质上是把读者从“手工时代”推进“批处理时代”的钥匙一次写好规则剩下交给解释器去重复。而 range() 函数、list(range()) 生成数字列表、min/max/sum 统计、列表推导式这四个东西一旦打通后面文件处理、数据清洗、爬虫解析、报表生成才有得谈。这一课适合两类人一类是刚看完列表、现在卡在“怎么让代码自己动起来”的零基础读者另一类是学过一点循环但每次写都靠猜边界、靠试运行的半新不旧的人。1.1 从“复制粘贴三行代码”到“一次处理一万条”先说清楚这个痛点有多真实。我给学员布置过一个很小的题把一份十个人的成绩逐个加 5 分。前十份提交里有六份是这么写的——score1 score1 5、score2 score2 5……一直排到score10。代码能跑结果也对问题在于这十行没有任何“结构”它只是十行。如果名单变成一百个人作者就会崩。for 循环解决的不是“省几个字”的问题而是把“对每一个元素做同一件事”这件事本身写成代码。思维上要从“我要处理第 1 个、第 2 个……”切换到“我要描述一条作用于任意元素的规则”。这个切换听着抽象落到纸面上就是一句话循环体里只写一次外面用 for 圈定范围。我在课上会做个小演示写十行赋值版本然后当着面改成三行循环再改成一行列表推导式。学员通常会被最后一步惊到但我会压住节奏——推导式是一层语法糖糖底下的循环才是理解的主体先能徒手写 for再谈一行流。这个顺序错了后面遇到循环里嵌条件、循环里改数据就会抓瞎。1.2 for 和 while 到底怎么选新手很常见的困惑是既然 while 也能循环为什么还要 for这两个不是替代关系是分工关系。我的判断标准很粗暴次数或集合是否已知。已知一个容器要逐个过一遍或者知道要重复多少次用 for只知道“直到某个条件不成立才停”用 while。求 1 到 100 的和次数是 100用 for让用户不停输入密码直到正确次数不确定用 while。用 while 去数列表元素是典型的错配它会把“计数变量自增”“边界判断”“越界风险”三件事全塞给你而 for 自动帮你做完了。对比维度for 循环while 循环驱动因素可迭代对象里的元素或 range 给出的次数一个布尔条件循环变量自动赋值每次取一个元素需要自己定义、自己更新越界风险基本没有走完就停有忘记自增或判断写反就死循环典型场景遍历列表、字符串、数字范围交互式输入、条件不定的重试新手容易出错的地方缩进、边界差一忘记更新变量导致卡死提示如果你写 while 的循环体里没有出现任何“会让条件变假”的语句先停下来检查这大概率是死循环。1.3 我安排这节课的顺序顺序不是随便排的它对应认知的递进。先讲语法骨架是因为 for 的行、冒号、缩进这三样东西必须固化成肌肉记忆否则后面所有内容都建在沙子上。再讲 range是因为数字列表的产生方式必须先落地学员得先能“造出 1 到 10”这堆数据才谈得上处理。接着讲数字列表的统计与切片把循环的结果真正用起来。然后是推导式作为熟练后的简化。最后一定是坑和排查这一节我从不砍因为第六课之后的作业难度会陡增没这一节学员会在缩进和边界上反复摔跤浪费两周时间。2. for 循环的语法骨架四个元素缺一个都不行2.1 for、in、冒号、缩进这四件套一个完整的 for 语句长这样scores [78, 92, 65, 88] for score in scores: print(score)四样东西必须齐全关键字for、循环变量score、关键字in加被遍历的对象行尾的英文冒号以及下一行的缩进。少了冒号报SyntaxError缩进没对齐报IndentationError这两个错误占了新手报错总量的一大半。我常跟学员说冒号的意思是“下面开始是我的地盘”缩进就是拿尺子划出来的地界地界之外的东西循环管不着。这里有个很关键的机制要讲透循环体里的代码会执行多少次、在什么时机执行取决于缩进层级。看下面这段total 0 for n in [1, 2, 3]: total total n print(累计:, total) print(循环结束最终结果:, total)前三行在循环里每轮都跑最后一行缩进退回来了只在循环结束后跑一次。很多人的 bug 就出在这里——本该放循环外的语句缩进去了于是一百次循环打印了一百遍本该放循环里的语句退出来了于是只算了最后一个元素。2.2 可迭代对象一摞等着被拿走的盘子in后面能放什么放“可以被一个个取出来的东西”。列表、字符串、range 对象、字典的键、文件的每一行都属于这一类。我喜欢用一摞盘子打比方for 循环就是伸手拿盘子拿一个处理一个拿完为止你不需要提前知道有几个。字符串也能遍历这常被忽略for ch in python: print(ch)会逐字符打印。这个特性在后面做文本统计数某个字出现几次时非常顺手。反过来说整数、浮点数不能直接放在 in 后面写for x in 5会报TypeError: int object is not iterable——“不可迭代”这个报错翻译成人话就是“这东西没法一个个取出来”。遇到这个报错第一反应是检查 in 后面是不是忘了套 range 或者 list。底层一点说for 循环第一步会对目标调用一次迭代协议拿到一个迭代器之后每轮问它“还有下一个吗”。这套机制对使用者是透明的但理解它有个好处同一个列表可以遍历多次而迭代器被消费完就空了。有些学员用生成器做完一次统计后想再遍历一遍结果什么都没打印就是踩在这里。2.3 循环变量怎么命名enumerate 什么时候上循环变量名不影响运行但影响三个月后你还认不认得这段代码。for i in scores能跑可读性差for score in scores一眼就懂。列表里装的是成绩就用 score是名字就用 name是商品就用 item。这条不是洁癖是给未来的自己留说明书。当需要同时拿到序号和元素时别自己维护计数器用enumeratenames [A同学, B同学, C同学] for index, name in enumerate(names, start1): print(f第{index}位{name})start1让编号从 1 开始符合人的阅读习惯。很多新手会写i 0然后在循环里i 1能跑但多了一个需要维护的变量就多了一个出错点。同样的道理两个列表一一配对遍历用zip比按下标去索引两个列表干净得多也避免了长度不一致时越界。3. range() 的三种写法和边界到底怎么算3.1 三种形态一张表说清range 是“生成一串整数”的工厂三种调用方式覆盖了绝大多数需求写法含义生成的序列常见用途range(5)从 0 开始到 5 之前0,1,2,3,4控制重复次数range(1, 6)从 1 开始到 6 之前1,2,3,4,5计数从 1 起的场景range(0, 10, 2)从 0 开始步长 20,2,4,6,8隔一个取一个range(5, 0, -1)从 5 开始倒着走5,4,3,2,1倒序处理其中最容易翻车的就是第二种。想要 1 到 5必须写range(1, 6)。我每期都会有人在作业里写range(1, 5)然后疑惑为什么少了 5。3.2 左闭右开怎么记别背画数轴我从不要求学员背“左闭右开”这个术语只教一个动作在纸上画一条数轴把两个数字标上去然后把右端点那个数圈起来打个叉叉左边那一格才是最后一个。range(1, 6)1 和 6 标出来6 打叉最后一个就是 5。这个动作做十遍肌肉记忆就有了。换个更好记的说法range 的两个参数其实是“起点”和“终点外一格”就像量身高时说“从 0 到 180 厘米”包含了 179.9但标记线画在 180。或者用排队类比range(1, 6)是“1 号站到位到 6 号位置前一位为止”。再补一条硬算公式序列长度等于 (stop - start) 除以 step 后向上取整。比如range(2, 11, 3)跨度 9除以 3 得 3元素是 2、5、8正好三个。会这个公式遇到“步长不是 1”的情况不会慌。3.3 负步长倒着数倒序有两种写法各有适用面。range(5, 0, -1)直接产出 5 到 1如果手里已经有列表用切片[::-1]更省事。注意负步长时起点必须大于终点否则得到空序列——range(1, 5, -1)什么都不产出还不报错这是最阴的一类 bug因为它静悄悄地什么也不做。我一般建议在写负步长的循环后先单独print(list(range(...)))看一眼结果再往下写。3.4 range 对象不是列表Python 3 里range(1000000)瞬间返回不占内存因为它并不真的把一百万个数字造出来而是“你问我要第几个我现算”。这叫惰性。好处是省内存代价是它不支持切片、不能直接相加、打印出来是range(0, 5)而不是[0, 1, 2, 3, 4]。想看到内容套一层 list。想求长度用len(range(1, 6))得到 5判断某个数在不在里面用3 in range(1, 6)得到 True。注意如果你是从很老的教程里学的 Python可能会看到“range 返回列表”的说法那是 Python 2 的遗留。判断标准很简单print(range(5))出来带方括号就是列表带 range 字样就是对象。4. 数字列表生成、统计、切片一条龙4.1 用 list(range()) 造一串数字数字列表就是元素全是数字的列表最常见的造法是list(range(...))numbers list(range(1, 11)) print(numbers) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]注意外面那层list()不能省。range(1, 11)只是“描述了一个范围”套上 list 才是“把范围内的数真的装进列表”。这一步的动机很实际range 只能生成等差数列而列表能装任意数字能改、能加、能排序、能切片。另一条路是先用循环加 append 一点点往里塞cubes [] for n in range(1, 6): cubes.append(n ** 3)这种“先建空列表、再逐个追加”的写法是循环与列表结合的经典范式值得练熟因为后面处理文件、爬数据基本都是这个套路。4.2 min、max、sum 与手算统计有了数字列表三个内置函数直接给出极值和总和data [88, 76, 95, 60, 92] print(min(data)) # 60 print(max(data)) # 95 print(sum(data)) # 411 print(sum(data) / len(data)) # 82.2求平均值必须手动写sum/lenPython 没有内置的 mean很多人第一次会去找data.mean()然后报错——列表没有这个方法那是别的数据处理库的写法。平均值这里有个坑空列表求平均值会触发除零错误如果数据来自文件读取遇到空文件就炸。稳妥的做法是先判空。再往上一层用循环做“带条件的统计”比如数出及格人数passed 0 for s in data: if s 60: passed 1 print(及格人数:, passed)这段代码里有三样东西值得强调计数器passed必须在循环外初始化为 0否则第一轮就报变量未定义是passed passed 1的简写缩进层级决定if在不在循环内。学员出错最多的不是逻辑想不明白而是把passed 0写进了循环体于是每轮都清零最后永远是 1。这个错误我见过至少二十次。4.3 列表推导式把三行压成一行上一节那段算立方的循环可以写成cubes [n ** 3 for n in range(1, 6)]读法是“对 range(1,6) 里的每个 n取出 n 的立方组成一个列表”。顺序记法把普通 for 循环的三行代码竖着叠——第一行是结果表达式n ** 3第二行是 for第三行放在最前面就变成了推导式。加上条件也简单[n ** 2 for n in range(1, 11) if n % 2 0]得到偶数的平方。推导式好用但我有一个明确的劝退边界超过一层 for、超过一个 if 就别用。见过学员写出带两个嵌套循环加条件的推导式一行占了屏幕大半出了 bug 根本没法插 print 调试。这种时候老老实实展开成循环可读性和可维护性都更高。推导式是给人看的不是给机器炫技的。4.4 切片与步长切片切片是列表的“截取”语法列表[起点:终点:步长]同样是左闭右开写法结果以 1 到 10 为例说明nums[:3][1,2,3]前三个nums[-3:][8,9,10]后三个nums[2:5][3,4,5]下标 2 到 4nums[::2][1,3,5,7,9]隔一个取nums[::-1][10,...,1]反转起点省了默认从头终点省了默认到尾三个都省就是整个列表的副本。切片不改变原列表这跟sort()和sorted()的区别一样是新手很爱混的点。要记住切片是复印不是撕原件。4.5 两个马上能用上的小案例第一个批量单位换算。一份以摄氏度记录的温度列表转成华氏度celsius [12, 18, 25, 31, 7] fahrenheit [c * 9 / 5 32 for c in celsius] print(fahrenheit)第二个从一长串数字里挑出符合区间的部分raw [1024, 87, 5000, 320, 12, 800] valid [x for x in raw if 100 x 1000] print(valid) # [320, 800] print(sum(valid)) # 1120这两个例子都不是玩具前者是数据清洗里的标准化后者是过滤异常值。学员做完这两个普遍会有一个“原来循环是干这个用的”的顿悟时刻比讲十遍概念管用。5. 新手最常撞的六个坑和排查表5.1 缩进类Tab 和空格混着用Python 靠缩进划分代码块所以缩进错误不是“格式问题”是“语法错误”。最常见的两种情况一是同一层级用了 Tab 又用了空格肉眼看对齐了解释器认为不对齐报TabError或IndentationError二是循环体忘了缩进print顶格写结果只有最后一行被执行。解决办法很土但有效统一用四个空格编辑器里设置“按 Tab 插入空格”。另外冒号打完回车编辑器一般会自动缩进不要手动再按一次空格去“微调”越调越乱。5.2 边界类差一错误需求写“打印 1 到 10”写成range(1, 10)只到 9。需求写“列表最后一个元素”写成nums[len(nums)]直接越界正确是nums[-1]或nums[len(nums) - 1]。这类错误的特点是不报错或报得很远逻辑错了但程序照跑。我的建议是养成一个小动作涉及 range 的地方写完后立刻在旁边打印一次list(range(...))或者它的长度用眼睛验一遍。三十秒的成本省掉半小时的排查。5.3 逻辑类遍历时改列表、累加器没初始化遍历列表的同时删除元素是入门阶段最经典的陷阱nums [1, 2, 3, 4, 5, 6] for n in nums: if n % 2 0: nums.remove(n)结果不是想象的只剩奇数而是漏删了元素。原因在于遍历是按位置推进的删掉一个元素后后面的整体前移循环指针也跟着走就跳过了一个。稳妥做法是用推导式生成新列表[n for n in nums if n % 2 ! 0]或者遍历副本for n in nums[:]。原则一句话遍历谁就别改谁。另一个高频 bug 是累加器位置。求和、计数、拼字符串这三种操作累加变量必须放在循环之前初始化且初始化那一行不能缩进进循环。5.4 类型类range 不吃小数、字符串和数字混算range(0, 1, 0.1)会直接报TypeError因为 range 只接受整数。想要 0 到 1 之间的 0.1 步长常见做法是用整数循环再除以 10[i / 10 for i in range(0, 11)]。这个换算思路在绘图刻度、分档统计里很常用。另一种类型坑是输入。从输入框拿到的东西是字符串5 1会报错必须先转成整数。而列表里混着字符串和数字时sum()也会直接崩。排查方法很简单在出问题的地方print([type(x) for x in data])一眼看出谁不是数字。5.5 排查速查表现象最可能的原因处理动作IndentationError缩进不一致或该缩进没缩进全选统一转换 Tab 为空格SyntaxError: invalid syntax行尾漏了冒号或中文标点检查 for 行末尾切英文输入TypeError: int object is not iterablein 后面直接放了数字套上range()或list()结果比预期少一个range 右端点写成了目标值本身右端点加 1循环体只执行了一次累加器或计数在循环内被重置把初始化语句移到循环外循环一次都不执行 / 死循环负步长方向写反 / while 条件永真打印 range 内容检查条件更新求和结果是个长字符串列表里混了字符串没转换逐元素int()或float()提示报错信息里的行号是朋友不是敌人。Python 的报错通常准确指向出错那一行或它的上一行先看最后一行报错类型再往上找。6. 带班实操练习怎么排、代码怎么调6.1 三道递进的练习题第一道纯 range 练手打印 1 到 20 的所有偶数再求它们的和。这道题把 range 边界、步长、累加三件事串起来做对说明语法过关。第二道数字列表统计给一组任意成绩输出最高分、最低分、平均分、及格率。这道题的坑在平均值和及格率的除零判断以及计数器位置。第三道综合应用生成 1 到 30 的平方列表只保留能被 3 整除的项输出列表和它们的总和。这道题可以做两遍一遍用普通 for 加 append一遍用推导式让学员自己感受两种写法的差异再讨论什么时候该用哪种。我特意把题量控制在三道因为第六课的重点是建立“循环思维”不是刷题量。三道题各做一个变体比囫囵做完十道有用得多。批改时我只看两件事累加变量的位置对不对边界有没有差一。这两处对了其余小毛病都好纠。6.2 调试习惯小数据先跑通学员最常犯的调试错误是拿真实数据直接开跑比如一万行的成绩单出错后无从下手。我的建议固定成三步。第一步把数据换成三五条手写的假数据比如[90, 60, 75]先确认逻辑跑通。第二步在循环体里加一行print把每轮的循环变量和累加结果打出来肉眼看走向是否符合预期。第三步确认无误后再换回真实数据。这三步多花两分钟能省掉大量猜测。还有个小技巧值得说把循环里的中间结果打印成“第几轮、当前元素、当前累计”三列格式比只打印一个数字有用得多。比如print(f第{i}轮 元素{n} 累计{total})出问题时一眼看出是从哪一轮开始偏的。6.3 几个绕不开的经验第一个经验关于列表推导式的使用节奏。我见过太多人在刚学会推导式后把所有循环都改成一行流包括那些带两三层判断、逻辑本来就复杂的代码。三个月后回头看自己都读不懂。我的判断标准是能一眼读完且不需要注释就懂用推导式否则老实展开。推导式的价值在于简化简单的循环不在于压缩复杂的逻辑。第二个经验关于数字列表的范围控制。生成 1 到 100 万这种大列表在 Python 里是可行的但要清楚它的内存成本——每个整数对象都有开销一百万个数不是一百万字节。真要处理大规模序列用 range 直接迭代就够了没必要先list()出来再遍历。这个区别在数据量小的时候完全看不出一旦上了规模就是几倍的差距。第三个经验关于代码的可读性投入。第六课之后学员的代码开始从十几行涨到几十行这时候变量命名、空行分组、适当注释的价值才开始显现。我会在这个阶段强制要求循环变量用有意义的名字累加变量叫total而不是t。这不是形式主义是因为调试的时候你会反复扫这段代码每一个含义模糊的名字都在消耗你的注意力。我自己带课这么些年最深的一个体会是for 循环这一课的难点从来不在语法语法半小时就能讲完。难在学员要接受一种新的思考方式——不再描述“第一步做什么、第二步做什么”而是描述“对每一个元素做什么”。这个转换有的人当场就通了有的人要写坏三四个程序才转过弯。所以这一课我从不赶进度宁可多留两道练习题多花半小时逐个看作业里的缩进和边界。基础阶段省下的时间后面都要以加倍的调试时间还回来。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑