CodeRoad Map 程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。
由 程序员柏风 独立维护 · 关于作者
学习 更多
条件与循环
这一课你将能做到
用 if/elif/else 写出多分支判断,并用 for/while 处理重复任务
熟练使用 range() 生成序列,正确区分 break、continue、else 三种循环控制
会写基础列表推导式,把「循环 + append」压缩成一行
为什么要学
程序之所以比人强,就强在两件事:会判断 (条件)和不喊累 (循环)。批量重命名 500 个文件是循环,文件类型不同走不同处理是条件,判断到第几个文件出错要跳过是 break/continue。这两块不熟,Python 就只是一台高级计算器。
人话:if 是岔路口——满足条件走这条路,否则走那条;for 是流水线——挨个处理每个东西;while 是闹钟——条件没满足就一直转。
先建立图像
if / elif / else —— 岔路口(只走一条)
score >= 90?
/ \
是 否
| |
"优秀" score >= 60?
/ \
是 否
| |
"及格" "不及格"
for x in [1,2,3] —— 流水线(每个都过一遍)
取 1 → 处理 → 取 2 → 处理 → 取 3 → 处理 → 结束
Java 与 Python 的 for 对照:
// Java:计数器循环
for (int i = 0; i < 5; i++) { ... }
# Python:遍历循环(更常写的是这种)
for i in range(5): ...
for name in names: ... # 直接遍历元素,不搞下标
跟着做
步骤 1:if / elif / else 完整分支
新建 control_demo.py:
score = 76
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 60:
grade = "C" # 76 落在这里
else:
grade = "D"
print(grade) # C
# 条件可以组合:and / or / not
age, vip = 20, False
if age >= 18 and not vip:
print("普通成人票") # 命中
输出:
C
普通成人票
要点:elif 从上到下短路匹配 ,命中一个就跳过所有后面的分支;所以范围判断要「从大到小」写,否则 score >= 60 写在最前会把 90+ 也接走。
步骤 2:Python 特有的链式比较与真值判断
# 链式比较:数学写法直接用
score = 76
print(60 <= score < 90) # True,等价于 score >= 60 and score < 90
# 真值判断:空的东西都是假
name = ""
items = []
if not name:
print("名字为空")
if not items:
print("列表为空")
# 三元表达式(条件表达式)
level = "高" if score >= 60 else "低"
print(level) # 高
输出:
True
名字为空
列表为空
高
判断「列表是否为空」用 if not items,不要写 if len(items) == 0——前者是 Python 惯用法。
步骤 3:for 遍历与 range()
# 遍历列表元素
fruits = ["苹果", "香蕉", "橘子"]
for f in fruits:
print(f"我喜欢{f}")
# range 三种用法
print(list(range(5))) # [0, 1, 2, 3, 4] stop 不含
print(list(range(1, 6))) # [1, 2, 3, 4, 5] start 到 stop
print(list(range(10, 0, -2))) # [10, 8, 6, 4, 2] 步长可以为负
# 带下标遍历:enumerate(不要手动维护 i)
for i, f in enumerate(fruits, start=1):
print(f"{i}. {f}")
我喜欢苹果
我喜欢香蕉
我喜欢橘子
[0, 1, 2, 3, 4]
[1, 2, 3, 4, 5]
[10, 8, 6, 4, 2]
1. 苹果
2. 香蕉
3. 橘子
需要下标时用 enumerate,不要写 for i in range(len(fruits)) 再 fruits[i]——能跑但不够 Pythonic。
步骤 4:while 与循环控制 count = 3
while count > 0:
print(f"倒计时 {count}")
count -= 1 # Python 没有 count--,必须写 -= 1
print("发射!")
# break:立刻跳出整个循环
for n in [3, 7, 11, 15, 20]:
if n % 2 == 0:
print(f"第一个偶数:{n}")
break # 找到 4 就停,后面不再看
# continue:跳过本次,继续下一轮
for n in range(1, 6):
if n % 2 == 1:
continue # 奇数跳过
print(n, end=" ") # 2 4
倒计时 3
倒计时 2
倒计时 1
发射!
第一个偶数:4
2 4
步骤 5:循环 + else(少见的语法) targets = [3, 7, 11]
for n in targets:
if n % 2 == 0:
print("发现偶数")
break
else:
# 循环正常跑完(没被 break 打断)才执行
print("全部是奇数")
while ... else 同理。场景:搜索失败后给提示。用得不多,但读到别人代码要知道它不是 「循环的 else 分支每次都走」。
步骤 6:列表推导式入门 nums = [1, 2, 3, 4, 5, 6]
# 普通写法:循环 + 条件 + append
squares = []
for n in nums:
squares.append(n ** 2)
print(squares)
# 推导式:一行搞定
print([n ** 2 for n in nums])
print([n for n in nums if n % 2 == 0]) # 过滤:只留偶数
print({n: n ** 2 for n in nums}) # 字典推导式
[1, 4, 9, 16, 25, 36]
[1, 4, 9, 16, 25, 36]
[2, 4, 6]
{1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36}
推导式读法:先读 for,再读 if,最后读最前面的表达式——「对 nums 里每个 n,若 n 是偶数,取 n」。
讲清楚要点
elif 是短路链 :多分支按顺序匹配,命中即停。范围条件按从特殊到一般、从大到小排,否则逻辑重叠。
for 是「遍历」不是「计数」 :Python 的 for 直接迭代对象(列表、字符串、字典、文件都能迭代),需要数字序列才请出 range()。
range(5) 不含 5 :和切片一样「含头不含尾」,range(1, 6) 才是 1~5。步长可负可实现倒序。
break 断整条,continue 跳本次 :嵌套循环里 break 只跳出最内层 。
while 必须有出口 :循环体内必须让条件趋向 False(如 count -= 1),否则死循环;Ctrl+C 强制中断。
推导式是可读性与效率的平衡 :一层推导式优于循环版;两层以上嵌套的推导式可读性反而差,老老实实写循环。
任何非空对象都为真 :0、""、[]、{}、None 为假,其余为真。这让 if items: 成为判空的惯用法。
你可能会懵的地方
Python 为什么没有 i++?
因为 Python 里整数是不可变对象,i++ 语义上等于「新建一个对象再绑定」,官方认为 i += 1 表达得更诚实。同时 for 循环本身面向迭代而非计数器,i++ 的主战场很小。
for i in range(len(list)) 这种 Java 风格写法行不行?
能跑,但不推荐。要元素直接 for x in list;要下标用 enumerate(list);要两个列表并行遍历用 zip(a, b)。
while True + break 是不是坏风格?
不是,反而是「读配置 → 处理 → 检查退出条件」场景的标准写法(比如读文件读到 EOF)。判断条件复杂、无法写在 while 头上时,while True + 明确的 break 点最清晰。
字典怎么循环?
for k in d: 遍历键;for v in d.values(): 值;for k, v in d.items(): 键值对。最后一个最常用。
嵌套循环里 break 只跳一层,想全跳怎么办?
常规做法是封装成函数用 return(第 5 课),或用标志变量。Python 没有带标签的 break(Java 有),这是刻意的——逼你把复杂循环拆函数。
错法对照 错法 问题 正解 if score >= 60 写在 if score >= 90 前面90+ 被 60 分支截胡 分支按范围从大到小/从特殊到一般排 if x == 5 or 6:永远为 True(6 本身为真) if x == 5 or x == 6: 或 if x in (5, 6):while 里忘了更新条件变量死循环 循环体内推进条件(count -= 1 等) for i in range(len(lst))Java 味,冗长 for x in lst / enumerate(lst)用 len(x) == 0 判空 能跑但不惯用 if not x:推导式里嵌套三层 if 天书 还原成普通循环
卡点急救
程序卡住不动 :八成是 while 死循环。终端 Ctrl+C 中断,检查循环条件是否推进。
条件永远不成立/永远成立 := 写成赋值?Python 里 if x = 5 是语法错误会直接报,所以更常见的是把 == 误写成 in 或搞反 and/or。print 出条件两侧的值逐个验证。
break 跳得比预期多/少 :嵌套循环里 break 只管最内层。用 print 标记每层循环走到了哪,或者把内层循环抽成函数。
推导式结果和预期不符 :从推导式还原成 for 循环逐行排查,改完再压缩回去。
range(1, 10) 少了 10 :含头不含尾,要 10 就写 range(1, 11)。
面试常问
range 和 xrange 的区别?(考历史理解)
Python 2 里 xrange 返回惰性生成器、range 一次生成整个列表;Python 3 中 xrange 被移除,range 本身就是惰性序列对象,遍历多少生成多少,不占大内存。答出「Python 3 的 range 已是惰性的」即可。
列表推导式和 for 循环 append,哪个快?为什么?
推导式通常更快。原因:推导式在字节码层面用了专用指令,减少了每轮 append 方法的属性查找与函数调用开销。但可读性优先级高于性能,复杂逻辑仍建议普通循环。
break、continue、pass 的区别?
break 终止整个循环;continue 跳过本次迭代进入下一轮;pass 是空占位符,什么也不做,仅满足语法结构。
for-else 中 else 何时执行?
循环未被 break 打断、正常结束后执行。典型场景是「搜索失败提示」。答出「else 对应的是 break 的反义」即可。
if not x 和 if x is None 有什么区别?
前者判断 x 是否为「假值」(None、空容器、0、空串都算);后者只判断 x 是否为 None 对象。x = 0 时 not x 为 True 但 x is None 为 False。判「没有值」用 is None,判「有没有内容」用 not x。
自测三问
range(3, 10, 2) 依次产出哪些数?range(5, 0, -1) 呢?
if x == 5 or 6 为什么是 bug?两种正确写法是什么?
for-else 的 else 什么时候执行?写一个使用场景。
小结一句话 if 管岔路、for 管流水线、while 管等待;记住 elif 短路、range 含头不含尾、break 只跳一层、推导式一行顶四行,控制流就毕业了。
延伸