ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

Python结构语句详解:条件判断与循环控制核心用法

Python结构语句详解:条件判断与循环控制核心用法 学Python有一段时间的人多半会卡在这样一个坎上变量、数据类型、运算符都会了但拿到一个实际问题还是不知道代码该怎么组织。原因很简单——你只学了“零件”还没学“骨架”。Python结构语句就是程序的骨架它决定了代码什么时候执行哪一段、哪些操作要重复多少遍。这篇文章是Python系列教程的第三篇专门讲条件判断if / elif / else、循环遍历for / while以及 break、continue、pass 这些控制关键字适合已经掌握变量、列表、字典等基础、准备开始写实际逻辑的读者。看完之后你会知道怎么让程序“做选择”和“重复劳动”也能避开新手最容易踩的缩进和死循环坑。1. 条件分支让程序学会做选择1.1 if / elif / else 的写法和执行顺序条件分支是所有编程语言里最直白的骨架。Python 的写法很固定关键字后面紧跟一个判断表达式表达式末尾要加英文冒号冒号下面就是这个分支要执行的代码块。代码块不需要像 C 语言那样用大括号包起来Python 全靠缩进识别同一个分支里的语句缩进必须保持一致。score 85 if score 90: grade A elif score 80: grade B elif score 70: grade C else: grade D print(评级:, grade)这里有三条新手必须搞清楚的执行规则。第一if / elif / else 从上往下逐个判断只要有一个条件成立执行完对应的代码块之后后面的 elif 和 else 都不会再看。上面这个例子score 85 的时候第一个条件 85 90 不成立接着判断 85 80 成立输出 B后面两个分支直接被跳过。第二elif 可以不写else 也可以不写但如果写了 elif它前面必须先有一个 ifelse 永远只能放在最后而且跟最近的 if 配对。第三冒号不能丢这是新手报 SyntaxError 最常见的原因之一。用编辑器写代码时如果某一行突然标红先低头看上一行末尾有没有冒号。嵌套的条件判断在实际需求里很常见比如先判断用户角色再判断这个角色有没有对应权限。嵌套本身没问题但层数一多缩进越来越深可读性直线下降。我自己的习惯是嵌套超过两层就考虑把逻辑拆成独立的小函数或者用“早返回”的结构——先把不满足条件的情况直接 return 掉主逻辑留在外层。写复杂的数据处理脚本时这个习惯能帮你省大量排查时间。1.2 判断表达式里的隐藏规则条件分支里放的判断表达式很多人以为只能是 True / False 或者比较运算的结果其实 Python 里任何对象都可以直接放在 if 后面做判断。这叫“真值测试”每个对象在布尔语境里都会被转成 True 或 False。记住这条规律——以下对象会被当作 FalseNone、数字 0包括 0.0、0j、空字符串 、空列表 []、空字典 {}、空元组 ()、空集合 set()。其他对象基本都是 True。values [0, 1, , hello, [], [0], None] for v in values: if v: print(repr(v), 为真) else: print(repr(v), 为假)运行结果会告诉你空列表为假、非空列表为真。这个特性非常实用判断一个列表是否为空新手写 len(items) 0老手直接写 if items:。两种都能跑但后者更简洁也更符合 Python 社区的惯用风格。判断字符串是否为空用 if text:判断字典里是否存在某个键则用 if key in data:。还有一个容易踩的坑是运算符优先级。Python 里 not、and、or 的优先级是从高到低也就是说 not 最先计算其次是 and最后是 or。写 a or b and c 时实际计算的是 a or (b and c)不是 (a or b) and c。遇到这种表达我的建议永远只有一个别省括号。给读者看、给自己以后维护看加上括号都更省脑力。另外很多新手把比较运算和赋值搞混if score 85 是语法错误要写成 if score 85。这个错误在笔试和日常 code review 里出现频率都极高。Python 还支持连续比较a b c 等价于 a b and b c判断数值范围时很顺手比如 0 score 100。三元表达式则适合做简单的二选一赋值status 成年 if age 18 else 未成年。需要注意它本质是表达式而不是语句只能用来产生值不能在里面写复杂逻辑。如果三元的分支逻辑超过一行建议干脆写完整的 if / else别为了省两个字符牺牲可读性。2. 循环让代码学会重复2.1 for 循环的正确姿势for 循环是 Python 里使用频率最高的结构语句。它的设计哲学是“遍历一切可迭代对象”列表、元组、字符串、字典、集合、文件对象都可以直接放在 in 后面。基本写法names [Alice, Bob, Charlie] for name in names: print(name)这里的 name 是循环变量每次循环自动从列表里取出一个元素赋给它。Python 的 for 不需要手动管理索引也不会出现“少循环一次”或者“数组越界”这类问题。想遍历从 0 开始的数字序列用 range 函数for i in range(10): print(i) for i in range(1, 10, 2): print(i)range(stop) 生成 0 到 stop-1range(start, stop) 生成 start 到 stop-1range(start, stop, step) 带步长。注意不管哪种写法右边界 stop 都是取不到的这是新手最容易犯的低级错误比如想输出 1 到 100 却写成 range(1, 100)实际只到 99。想输出 1 到 100 要写 range(1, 101)。字典的遍历也经常用到。默认遍历字典拿到的是键同时要键和值用 items() 方法只要值用 values()。既想要序号又想要元素本身用 enumeratewords [apple, banana, cherry] for idx, word in enumerate(words): print(idx, word)enumerate 省去了自己维护计数器的麻烦默认从 0 开始想从 1 开始就传第二个参数enumerate(words, start1)。再讲一个用的人不多但关键时候管用的东西for-else。Python 的 for 循环后面可以跟一个 else 子句它的语义是如果循环正常走完中途没有被 break 打断就执行 else 里的代码。最经典的例子是判断质数num 7 for i in range(2, num): if num % i 0: print(num, 不是质数) break else: print(num, 是质数)如果循环里发现了因子break 跳出else 不执行如果 2 到 num-1 全试完都没发现因子循环正常结束else 执行输出质数。注意 else 和 for 是平级的缩进要和 for 对齐不是和 if 对齐。很多教材不讲这个但关键时候它能让“是否找到目标”这类逻辑少写一个标志变量很值得掌握。2.2 while 循环与循环控制while 循环适合“不知道要循环多少次只知道满足某个条件就继续”的场景。写法是 while 后面跟条件条件为真就一直执行循环体count 0 while count 5: print(当前计数:, count) count 1这里 count 1 是循环能结束的关键。新手写 while 最容易出的事故就是忘记在循环体里修改控制条件导致死循环。比如上面漏掉 count 1count 永远是 0条件永远为真程序就卡死了。在命令行里按 CtrlC 能中断但如果你把这行代码嵌进自动化脚本整个流程可能都会卡住排查时还很难定位。while 和 for 共用一套控制关键字break、continue、pass。break 是立刻结束整个循环不管后面还有多少轮直接跳出。continue 是跳过本轮剩余代码进入下一轮。pass 是什么都不做的占位符通常用来补结构。看一个典型的输入校验循环while True: num input(请输入一个数字输入 quit 退出: ) if num.lower() quit: print(再见) break if not num.isdigit(): print(输入不合法请重新输入) continue print(平方结果:, int(num) ** 2)这是“用户输入校验”的标准模板。while True 构造无限循环靠 break 退出输入不合法时用 continue 回到输入位置而不是继续往下执行。命令行交互工具、菜单选择界面几乎都长这样务必掌握。break 和 continue 在嵌套循环里有一条特别容易误解的规则它们只作用于自己所在的最近一层循环不会跳出外层。双层循环里写 break只是结束内层循环外层继续跑。这个规则用好很省事用错很致命——排查半天也找不到为什么外层还在执行。至于 pass最常见的用途是暂时空着函数体或类定义让代码先通过语法检查后续再补实现。它本身的执行效果就是什么都没发生所以不要指望它有任何“跳过”作用那是 continue 的活。while 后面也能跟 else语义和 for-else 一样循环没被 break 打断就执行但用得比 for-else 还少知道有这回事即可。什么时候用 for、什么时候用 while我的经验是能明确知道要遍历的对象或者循环次数预先确定就用 for只能靠条件判断决定是否继续、次数不确定尤其是和用户输入、网络请求重试相关的场景就用 while。3. 把结构语句串起来三个实战场景3.1 数据筛选与统计if 加 for 的万能组合理论讲完看真实需求。假设有一组学生成绩要把及格的挑出来再算平均分。这个需求用 if 加 for 组合解决scores [67, 89, 45, 92, 58, 73, 81] passed [] for s in scores: if s 60: passed.append(s) print(及格名单:, passed) print(平均分:, round(sum(scores) / len(scores), 2))这段代码背后是“遍历—判断—收集”模式它能覆盖大量数据处理场景过滤日志里的错误行、从商品列表挑出折扣商品、从传感器读数筛出异常值本质上都是同一个骨架。Python 还提供了列表推导式来压缩这种模式一行搞定passed [s for s in scores if s 60]执行逻辑和上面的 for 循环完全等价只是更紧凑。我的个人建议是列表推导式一定要会写会读但刚切换过去时先在草稿纸上把它展开成 for 循环确认逻辑。推导式里再套推导式或者里面塞了复杂条件分支还是老老实实用普通循环加 if可读性永远比“代码短”重要。3.2 嵌套循环构建邻接矩阵第二个场景来自图论和算法题也是搜索热度很高的需求——构建邻接矩阵。假设图有 n 个节点边用元组列表表示要把边关系写进一个 n×n 的矩阵有边的位置填 1没边的填 0。新手最容易写出的错误版本是n 5 matrix [[0] * n] * n # 错误示范这个写法看起来没有任何问题实际上每一行都是同一个列表对象的引用。改 matrix[0][1] 1你会发现 matrix[1][1]、matrix[2][1] 全都变成了 1因为所有行共享同一块内存。正确写法是用列表推导式每一行都新建一个独立的列表n 5 edges [(0, 1), (1, 2), (2, 3), (3, 4), (0, 4)] matrix [[0] * n for _ in range(n)] for u, v in edges: matrix[u][v] 1 matrix[v][u] 1 # 无向图两个方向都填 for row in matrix: print(row)这里 [[0] * n for _ in range(n)] 里的 _ 是惯例写法表示“这个循环变量我不关心它的值”纯粹用来控制生成 n 行。[0] * n 生成一行 n 个零推导式每跑一次就新建一行行与行互不干扰。这个坑我当年实际踩过一次排查了很久才发现是“用乘法复制列表时共享了引用”。顺便说这正是 Python 算法题里大量隐藏坑的来源凡是“用乘法创建嵌套列表”的操作都要警惕别名问题。如果算法题里遇到像“李白打酒”这类经典问题本质上也是循环结构的练习。题目大意李白开始提着一定量的酒遇见酒店就翻倍遇见花就喝掉一斗三次遇店三次遇花之后酒刚好喝光问初始有多少酒。顺着推不好下手倒过来用一个循环就清楚了wine 0 for _ in range(3): wine 1 # 逆着“见花喝一斗” wine / 2 # 逆着“遇店加一倍” print(wine) # 0.875循环把三次“遇店—遇花”的过程逆向执行得到初始 0.875 斗酒。这个例子不求记住答案关键是体会“正向模拟困难时倒推往往能用一个简单的循环解决”的思维方式。3.3 循环里处理异常输入重试模板第三个场景是真实脚本绕不开的——和用户交互时做异常处理。用 input 读取数字时用户可能输入“abc”直接 int() 转换就会抛出 ValueError 终止程序。用 while 加 try / except 做重试循环是标准解法while True: try: num float(input(请输入一个数字: )) break except ValueError: print(输入的不是合法数字请重新输入) print(你输入的是:, num)try 块里只要成功完成转换break 立刻退出循环转换失败则进入 except提示之后继续下一轮循环。“try-except while True break”这套组合我愿称之为命令行脚本里最值得背下来的模板之一。它在读取文件、请求接口、解析 JSON 等场景里同样适用核心思想都一样把可能出错的步骤包进 try把重试的驱动力放在 while 上。4. 常见问题与排查实录4.1 IndentationError缩进引发的血案缩进是 Python 和 C、Java 最大的区别之一也是新手报错数量排行榜的榜首。IndentationError: unexpected indent 的意思是“出现了意外的缩进”常见原因有三个if / for / while 代码块内部语句顶格写了同一个代码块内有的行用了 4 个空格、有的行用了 Tab复制粘贴时把不同编辑器的缩进风格混在一起。解法很粗暴在编辑器里开启“显示空白字符”把 Tab 全部替换成空格然后重新整理缩进。用 PEP 8 的规定统一为 4 个空格是社区公认的做法。VS Code 里按 CtrlShiftP输入 Convert Indentation to Spaces一步搞定。另一个容易混淆的是逻辑缩进错误。Python 只检查缩进层级是否一致不检查你的缩进是否符合预期语义。比如if score 60: print(及格) print(这句也在 if 里) print(这句在 if 外面)第三行 print 因为缩进减少已经不属于 if 分支了。这种程序不会报错但运行结果和预期完全不同排查的时候比 IndentationError 更隐蔽。我的经验是先看编辑器里的缩进辅助线再确认目标语句归属于哪个层级不要靠肉眼数空格。4.2 遍历时删除元素最常见的逻辑坑前面邻接矩阵是“创建”时的别名坑这里还有一个“修改”时的迭代坑。在遍历列表的同时删除元素会因元素索引移位导致部分元素被跳过。看这个例子nums [1, 2, 4, 6, 8] for n in nums: if n % 2 0: nums.remove(n) print(nums) # 实际输出 [1, 4]预期是删掉所有偶数得到 [1]实际得到 [1, 4]因为 remove 改变了列表长度for 循环内部的索引却还在照常递增4 被跳过去了。正确做法有三种遍历列表的副本for n in nums[:]先记录要删的元素再统一删除或者直接用列表推导式生成新列表。最推荐最后一种nums [1, 2, 4, 6, 8] nums [n for n in nums if n % 2 ! 0] print(nums) # [1]同样的道理适用于字典——遍历字典时往里加键或者删键会直接报 RuntimeError: dictionary changed size during iteration因为字典的哈希表在迭代期间不允许结构性修改。遇到这个错就把要改的键先收集成列表遍历结束后再统一操作。4.3 高频易错点速查表报错或现象常见原因解决办法SyntaxError: invalid syntaxif / for / while 行尾漏冒号、括号不配对检查冒号用编辑器高亮检查括号匹配IndentationError: unexpected indentTab 和空格混用、代码块缩进不统一统一为 4 个空格开启显示空白字符程序卡死、输出刷屏while 条件恒为真循环体没修改控制变量检查循环体里的变量更新临时加 print 观察遍历列表删除元素结果不对边遍历边 remove元素被跳过用列表推导式或遍历 nums[:] 副本整数和浮点数比较总是 False浮点数二进制存储误差0.1 0.2 不等于 0.3用 abs(a - b) 1e-9 判断相等或 round 后比较在函数内给全局同名变量赋值报错赋值让该变量被解释为局部变量需要修改全局变量时用 global 声明循环次数少一次range 的右边界取不到想包含 stop 值就写成 range(开始, stop 1)for 后面的 else 没执行循环被 break 提前打断检查是否在某个条件下 break 提前退出了这张速查表里的问题我在帮朋友看代码时几乎每一类都见过。尤其是浮点数比较很多人第一次跑 0.1 0.2 0.3 得到 False 都会懵其实这是所有现代编程语言的通病不是 Python 的 bug。最后分享一点个人体会。结构语句本身并不难难的是“什么时候用哪种”的判断力。我自己的学习路径是先把 if / elif / else、for、while 各写十遍确保能默写然后找一个综合小项目比如命令行记账本或者读取 CSV 文件筛选数据把所有结构串起来用最后才是刻意读别人的代码观察别人在什么场景下用了 while True、什么场景下用了 for-else、哪里用了列表推导式。等到你写代码时不再需要停下来想“这里该用 if 还是 while”结构语句就算是真正内化了。
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表