返回专题首页

Python 专题

流程控制与表达式:条件分支、循环与推导式入门

当我们掌握了基本数据类型和容器后,下一步就是让代码真正“动起来”。条件分支决定程序走哪条路,循环决定它如何反复处理数据,而推导式则体现了 Python 在表达上的简洁与高效。

Python 专题第 06 篇 / 39 篇9 分钟

当我们掌握了基本数据类型和容器后,下一步就是让代码真正“动起来”。条件分支决定程序走哪条路,循环决定它如何反复处理数据,而推导式则体现了 Python 在表达上的简洁与高效。

这一节会从最基础的 ifforwhile 出发,再逐步过渡到推导式、enumeratezip 等常用增强写法,帮助你把“能写”进一步变成“写得清楚、写得顺手”。

条件分支:if / elif / else

流程控制里最先接触到的,通常就是条件分支。它的核心问题其实非常简单:在不同条件下,程序到底应该走哪条路径。

Python 中最常见的条件结构就是:

score = 85

if score >= 90:
    print("A")
elif score >= 60:
    print("Pass")
else:
    print("Fail")

这里最需要尽早建立的两个习惯分别是:

  • 条件分支判断的是语义,而不是单纯堆很多表达式;
  • 分支顺序很重要,越具体、越优先的条件通常应该放在前面。

很多初学者在写 if 时,容易掉进两个坑。

第一个坑是把条件写得太散。比如明明是在判断用户状态,却把不同字段、不同语义的判断全揉在一层里,结果逻辑越来越难读。第二个坑是分支顺序写反。比如先写一个很宽泛的条件,后面更具体的条件就永远走不到了。

所以,条件分支真正重要的不是语法本身,而是问清楚:

  • 我到底在区分哪几种情况?
  • 这些情况有没有优先级?
  • 哪些条件是互斥的,哪些是补充判断?

另外,Python 里的条件判断不一定非要和显式布尔值绑定。只要某个对象能参与真值判断,它就可以直接进入 if

name = ""

if name:
    print("has name")
else:
    print("empty")

这和上一节讲到的真值规则是连在一起的。只不过这里也要提醒一句:写得简洁很好,但不要把“值为空”和“值不存在”混为一谈。必要的时候,还是要明确判断 is None 或长度是否为 0。

所以,if / elif / else 看起来是最普通的语法,但它其实是在训练你一件更重要的事:把问题拆成清晰的分支结构。

循环语句:forwhile

条件分支解决的是“往哪走”,而循环解决的是“做多少次”。当你需要重复处理一批数据、重复执行某个动作时,循环就会成为最自然的表达方式。

Python 里最常见的循环有两种:

  • for:更适合遍历一批已有数据;
  • while:更适合在某个条件持续成立时反复执行。

先看 for

items = ["python", "fastapi", "sqlalchemy"]

for item in items:
    print(item)

对 Python 来说,for 并不只是“从 0 循环到 N”,而更像是“把一个可迭代对象里的元素一个个拿出来处理”。这也是为什么它在列表、元组、字典、集合、字符串等场景下都会非常常见。

while 更像“条件驱动”的循环:

count = 0

while count < 3:
    print(count)
    count += 1

它适合表达“只要某个条件还成立,就继续执行”。比如轮询、重试、等待条件变化等场景,while 都会比较自然。

不过,对于大多数初学阶段的代码来说,for 往往比 while 更安全也更清晰。因为 while 如果忘了更新条件,很容易写出死循环:

while True:
    ...

死循环本身不是错,很多服务程序本来就是长期运行的。但如果你只是想写一个普通逻辑,却不小心让条件永远成立,那问题就会非常直接。

所以,一个很实用的经验是:

  • 能用 for 描述“遍历数据”时,优先用 for
  • 只有当问题本质上是“条件持续成立就继续执行”时,再考虑 while

breakcontinueelse

循环里还有几个非常常见的关键字:

  • break:提前结束整个循环;
  • continue:跳过本轮,直接进入下一轮;
  • else:当循环正常结束而不是被 break 中断时执行。

先看 breakcontinue

for num in [1, 2, 3, 4]:
    if num == 3:
        break
    print(num)
for num in [1, 2, 3, 4]:
    if num % 2 == 0:
        continue
    print(num)

它们的作用很明确,但使用时也要有一个边界意识:如果一个循环里连续出现很多 breakcontinue,往往说明这段逻辑已经开始变得难读,可能需要拆成更清晰的条件结构或函数。

至于循环里的 else,它算是 Python 里一个比较特别的写法。很多人第一次看到都会疑惑:“循环为什么还能接 else?”

你可以把它理解成:

  • 如果循环是正常跑完的,就执行 else
  • 如果循环中途被 break 打断,就不执行 else

例如:

for item in [1, 2, 3]:
    if item == 5:
        break
else:
    print("not found")

这类写法在“查找是否命中”场景里会比较自然,但如果你觉得可读性不够强,也完全可以改写成更显式的方式。还是那句话:Pythonic 不等于越特殊越好,而是越贴合问题越好。

推导式入门:让表达更紧凑

当你开始熟悉循环之后,就会遇到 Python 很有代表性的表达能力之一:推导式。

推导式的本质,其实可以理解为:把“遍历 + 处理 + 生成新结构”压缩成一行更紧凑的表达。

比如,我们想把一组数字都乘以 2:

nums = [1, 2, 3]
doubled = [num * 2 for num in nums]

和先写空列表、再循环追加相比,推导式会更紧凑,也更符合“我要生成一个新结构”的语义。

但这里有一个非常重要的前提:推导式适合简单、单一、可一眼看清的转换逻辑。

一旦逻辑变复杂,比如嵌套多层条件、多重循环或带有副作用操作,推导式就很容易从“优雅”变成“难读”。所以学推导式,不只是学会写,更是学会什么时候应该收手。

列表推导式

列表推导式是最常见的一种推导式。典型写法包括:

nums = [1, 2, 3, 4]
evens = [num for num in nums if num % 2 == 0]

它可以很自然地表达:

  • 从原集合里筛选部分元素;
  • 对每个元素做变换;
  • 最终得到一个新的列表。

如果你发现自己在写这样的模板:

result = []
for item in items:
    result.append(...)

那往往就可以停下来想一下:这里是不是可以改写成列表推导式?

当然,也不是所有 append 都必须改成推导式。关键仍然是可读性。如果循环体里已经包含复杂判断或多步处理,普通循环依然可能更清楚。

字典与集合推导式

除了列表,字典和集合也都有自己的推导式形式。

字典推导式适合“生成键值映射”:

nums = [1, 2, 3]
squares = {num: num * num for num in nums}

集合推导式适合“生成去重后的结果集合”:

words = ["Python", "python", "FastAPI"]
lowered = {word.lower() for word in words}

它们背后的思路和列表推导式其实是一致的,区别只在于最终目标结构不同。

所以,推导式真正值得掌握的不是“语法模板有多少种”,而是看见一个场景时,你能否意识到:这里本质上是在生成一个新集合结构,而不是在执行一堆命令式步骤。

enumeratezip 与循环增强

当你开始熟悉循环之后,很快就会遇到两个特别实用的小工具:enumeratezip

先看 enumerate。它的作用,是在遍历元素的同时,把索引也一起带出来:

items = ["a", "b", "c"]

for index, item in enumerate(items):
    print(index, item)

这比自己手动维护计数器更清楚,也更不容易出错。只要你既需要元素本身,又需要它的位置,enumerate 基本都值得优先考虑。

再看 zip。它的作用,是把多个可迭代对象按位置配对:

names = ["Colin", "Alice"]
scores = [95, 88]

for name, score in zip(names, scores):
    print(name, score)

只要你需要“并排处理两组数据”,zip 就会非常自然。它的优势是能把“这两个列表本来就是一一对应关系”清楚地表达出来,而不是靠索引硬凑。

所以,enumeratezip 其实都属于“让循环更语义化”的工具:

  • enumerate 解决“元素 + 索引”;
  • zip 解决“多组数据并排遍历”。

它们本身并不复杂,但会显著改善代码的表达质量。

什么时候该写得更直接一些?

学到这里,很容易出现一个新的倾向:既然 Python 提供了这么多简洁写法,那是不是应该尽量把代码写得越短越好?

答案其实是否定的。

Python 鼓励简洁,但简洁从来不是目标本身。真正的目标始终是:让代码更清楚地表达问题。

所以,一个非常重要的判断标准是:

  • 如果一行推导式能让逻辑一眼看明白,那很好;
  • 如果一行推导式让你必须停下来反复数括号、读条件、想顺序,那它就已经开始过度了。

比如下面这种简单场景,推导式很合适:

evens = [num for num in nums if num % 2 == 0]

但如果你开始写多重嵌套、多个条件、再混入复杂函数调用,那么普通循环往往反而更清楚。

这背后其实对应的是一个更长期的编码判断:不要为了展示“我会这个语法”而牺牲可读性。

代码最终不是写给解释器看的,解释器什么都能读;代码更重要的读者,其实是未来的自己和团队里的其他人。

所以,真正成熟的写法不是“能不能写得更短”,而是“哪种写法最能把当前问题表达清楚”。这也是我们后面讲函数、模块和工程结构时会不断回到的原则。

总结与预告

这一节我们让数据和逻辑真正“动”了起来,掌握了条件判断、循环结构以及 Python 很有代表性的推导式写法。写法只是表层,更重要的是开始学会用更合适的结构表达问题。

下一节我们会继续向“代码组织”迈进,把零散逻辑抽成函数,系统理解参数、返回值与作用域。