一文详解Python的流程控制if/for/while

 更新时间:2026年07月01日 09:38:11   作者:码流怪侠  
本文详细解析Python流程控制,涵盖if/elif/else、for/while循环、match-case模式匹配,通过实操Demo展示猜数字游戏与简易计算器,助你掌握条件语句、循环结构、模式匹配等最佳实践,需要的朋友可以参考下

本文覆盖:条件语句(if/elif/else + 三元)、循环语句(for/while + else 子句)、range/enumerate/zip 并行迭代、break/continue/pass 循环控制、match-case 模式匹配(3.10+)、常见陷阱与最佳实践,最后用两个实操 Demo 收尾。

1. 介绍:为什么需要流程控制

1.1 一句话理解

流程控制 = 程序的「大脑决策系统」。没有流程控制的程序就是一条直线——从第一行执行到最后一行,中间不做任何判断、不重复任何步骤。现实中哪有这么简单的活儿?

1.2 三大基本结构

所有编程语言的流程控制都围绕这三个结构展开:

结构作用Python 关键字
顺序结构代码从上到下依次执行(默认行为)
选择结构根据条件决定走哪条路if / elif / else / match-case
循环结构重复执行某段代码for / while

1.3 Python 的特殊之处

跟 C/Java 比,Python 的流程控制有几个显著区别:

# 1. 没有大括号 {},靠缩进划分代码块
if True:
    print("缩进就是命")
    print("缩进错了就 SyntaxError")

# 2. 循环可以带 else 子句(是的你没看错,循环也有 else)
for i in range(3):
    print(i)
else:
    print("循环正常结束(没被 break)")

# 3. 条件表达式不用括号包裹(当然加了也不报错)
if x > 0:  # ✓
if (x > 0):  # ✓ 但多余

2. 条件语句:if / elif / else 与三元表达式

2.1 原理:Python 的真值测试

Python 的条件判断不是「判断 True/False」,而是真值测试(truthiness testing)。任何对象都能被 if 测试,Python 会调用内置的 bool() 函数来决定走哪条路。

# bool() 的底层逻辑(伪代码)
def bool(obj):
    # 1. 先找 __bool__ 方法
    if hasattr(obj, '__bool__'):
        return obj.__bool__()
    # 2. 再找 __len__ 方法
    if hasattr(obj, '__len__'):
        return obj.__len__() > 0
    # 3. 都没有?默认 True
    return True

假值(Falsy)清单

以下对象在 if 中等价于 False

类型假值说明
NoneTypeNone空对象
boolFalse布尔假
int0, 0整数零
float0.0浮点零
complex0j复数零
str""空字符串
list / tuple[], ()空序列
dict / set{}, set()空映射/集合
rangerange(0)空范围
# 验证假值
for val in [None, False, 0, 0.0, "", [], {}, set(), range(0)]:
    print(f"{repr(val):>10} -> {'假值' if not val else '真值'}")

# 输出:
#      None -> 假值
#      False -> 假值
#         0 -> 假值
#       0.0 -> 假值
#         '' -> 假值
#        [] -> 假值
#        {} -> 假值
#      set() -> 假值
#   range(0, 0) -> 假值

踩坑点: 0.0 是假值,但 0.0000001 不是。别用浮点数做条件判断,精度问题会咬人。

2.2 if / elif / else 完整语法

# 完整结构
if condition_1:
    # 条件1为真时执行
    pass
elif condition_2:
    # 条件1为假、条件2为真时执行
    pass
elif condition_3:
    # 前面都假、条件3为真时执行
    pass
else:
    # 以上条件全假时执行(可选)
    pass

执行流程

condition_1 ──True──▶ 执行代码块1 ──▶ 跳出整个if
     │
   False
     ▼
condition_2 ──True──▶ 执行代码块2 ──▶ 跳出整个if
     │
   False
     ▼
condition_3 ──True──▶ 执行代码块3 ──▶ 跳出整个if
     │
   False
     ▼
  else(可选)──▶ 执行else代码块

实际示例:成绩等级判定

def grade_level(score: float) -> str:
    """根据分数返回等级"""
    if score >= 90:
        return "A - 优秀"
    elif score >= 80:
        return "B - 良好"
    elif score >= 70:
        return "C - 中等"
    elif score >= 60:
        return "D - 及格"
    else:
        return "F - 不及格"

# 测试
for score in [95, 85, 75, 65, 55]:
    print(f"{score}分 -> {grade_level(score)}")

# 输出:
# 95分 -> A - 优秀
# 85分 -> B - 良好
# 75分 -> C - 中等
# 65分 -> D - 及格
# 55分 -> F - 不及格

C++ 对比: Python 没有 switch 语句(3.10 前没有,3.10 后用 match-case 替代)。多个 elif 就是 Python 式的 switch。在 C++ 里你可以 switch(score / 10),Python 里通常用 elif 链或者查表法(bisect 模块)。

2.3 三元表达式(条件表达式)

当 if-else 只有一个表达式时,Python 提供了简洁的三元写法:

# 语法:value_if_true if condition else value_if_false
result = "成年" if age >= 18 else "未成年"

# 等价于
if age >= 18:
    result = "成年"
else:
    result = "未成年"

嵌套三元(谨慎使用)

# 三层嵌套三元 —— 能用但别滥用
status = "优秀" if score >= 90 else ("及格" if score >= 60 else "不及格")

# 更推荐拆开写
if score >= 90:
    status = "优秀"
elif score >= 60:
    status = "及格"
else:
    status = "不及格"

踩坑点: 三元表达式的求值顺序是先判断条件,再求值对应分支,不是两个分支都求值。

# 安全:只有条件为真时才调用 expensive_func()
result = cheap_value if condition else expensive_func()

2.4 条件组合:and / or / not

# and:两边都真才真(短路:左边假就不看右边了)
if age >= 18 and has_id:
    print("可以进入")

# or:一边真就真(短路:左边真就不看右边了)
if is_vip or is_admin:
    print("有特权")

# not:取反
if not is_banned:
    print("账号正常")

短路求值的妙用

# 模式1:默认值赋值(Python 3.8+ 用海象运算符更优雅)
name = user_input or "匿名"

# 模式2:安全调用(避免 None 上的属性访问)
# 如果 obj 不为 None,才调用 obj.method()
obj is not None and obj.method()

# 模式3:链式比较(Python 独有,C++ 不行)
if 0 <= score <= 100:
    print("合法分数")

# 等价于
if 0 <= score and score <= 100:
    print("合法分数")

C++ 对比: C++ 里 0 <= score <= 100 会被解析成 (0 <= score) <= 100,即先算 0 <= score 得到 true/false(1/0),再拿这个值跟 100 比——永远为真!Python 的链式比较是语法糖,会正确展开成 0 <= score and score <= 100

3. 循环语句:for / while 与 else 子句

3.1 for 循环:遍历的艺术

Python 的 for 不是 C 的 for(i=0; i<n; i++),它是基于迭代器协议的——每次从可迭代对象里取一个元素,直到取完。

# 基本语法
for element in iterable:
    # 对每个 element 执行
    pass

# 遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
    print(fruit)

# 遍历字符串
for char in "Hello":
    print(char, end=" ")  # H e l l o

# 遍历字典
person = {"name": "yance", "age": 30, "role": "blogger"}
for key in person:            # 默认遍历 key
    print(key, person[key])
for key, value in person.items():  # 同时取 key 和 value
    print(f"{key}: {value}")

迭代器协议底层原理

# for 循环的等价伪代码
iterator = iter(iterable)        # 调用 iterable.__iter__()
while True:
    try:
        element = next(iterator)  # 调用 iterator.__next__()
        # 执行循环体
        ...
    except StopIteration:         # 迭代器耗尽
        break
# 手动模拟 for 循环
my_list = [10, 20, 30]
it = iter(my_list)
print(type(it))        # <class 'list_iterator'>
print(next(it))        # 10
print(next(it))        # 20
print(next(it))        # 30
# print(next(it))      # StopIteration!

3.2 while 循环:条件驱动

# 基本语法
while condition:
    # condition 为真时反复执行
    pass

# 倒计时
count = 5
while count > 0:
    print(f"倒计时:{count}")
    count -= 1
print("发射!🚀")

# 输出:
# 倒计时:5
# 倒计时:4
# 倒计时:3
# 倒计时:2
# 倒计时:1
# 发射!🚀

while True + break 模式

# 经典模式:无限循环 + 条件退出
while True:
    user_input = input("输入 quit 退出:")
    if user_input == "quit":
        break
    print(f"你输入了:{user_input}")

踩坑点: while 循环最容易犯的错就是忘记更新条件变量,导致死循环。

# ❌ 死循环!count 永远是 5
count = 5
while count > 0:
    print(count)
    # 忘了 count -= 1

# ✓ 正确
count = 5
while count > 0:
    print(count)
    count -= 1

3.3 循环的 else 子句(Python 独有特性)

这是 Python 最反直觉的特性之一——循环也有 else

语义

  • for...else:循环正常结束(没被 break 打断)时,执行 else
  • while...else:条件变假导致循环结束时(没被 break 打断),执行 else
# for...else:查找质数
for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(f"{n} = {x} * {n // x}")
            break
    else:
        # 如果内层 for 没被 break(即没找到因子),说明 n 是质数
        print(f"{n} 是质数")

# 输出:
# 2 是质数
# 3 是质数
# 4 = 2 * 2
# 5 是质数
# 6 = 2 * 3
# 7 是质数
# 8 = 2 * 4
# 9 = 3 * 3

理解 else 的触发条件

# 情况1:正常结束 -> else 执行
for i in range(3):
    print(i)
else:
    print("else 执行了")  # ✓ 会执行

# 情况2:被 break -> else 不执行
for i in range(3):
    print(i)
    if i == 1:
        break
else:
    print("else 执行了")  # ✗ 不会执行
循环执行流程:

for/while ──▶ 循环体
                │
        ┌───────┴───────┐
        │               │
    遇到 break      正常结束
        │               │
        ▼               ▼
    跳出循环        执行 else 块
    (跳过 else)    然后继续后续代码

踩坑点: 很多人把 for...else 理解成「循环没执行时才走 else」,这是错的。空循环也会走 else:

for i in range(0):  # 循环体一次都不执行
    pass
else:
    print("else 照样执行")  # ✓ 会执行,因为没有 break

最佳实践: 如果你觉得 for...else 难读,用标志变量替代完全没问题:

found = False
for x in range(2, n):
    if n % x == 0:
        found = True
        break
if not found:
    print(f"{n} 是质数")

4. range / enumerate / zip 并行迭代

4.1 range:生成整数序列

range 是 Python 中最常用的迭代工具之一,它不实际生成列表,而是一个惰性序列对象。

# 三种形式
range(stop)            # 0, 1, 2, ..., stop-1
range(start, stop)     # start, start+1, ..., stop-1
range(start, stop, step)  # start, start+step, start+2*step, ...

# 基本用法
for i in range(5):
    print(i, end=" ")      # 0 1 2 3 4

for i in range(2, 6):
    print(i, end=" ")      # 2 3 4 5

for i in range(0, 10, 2):
    print(i, end=" ")      # 0 2 4 6 8

# 倒序
for i in range(10, 0, -1):
    print(i, end=" ")      # 10 9 8 7 6 5 4 3 2 1

range 的惰性特性

r = range(1000000)  # 不会占内存!
print(type(r))       # <class 'range'>
print(len(r))        # 1000000
print(r[0])          # 0    —— 支持索引
print(r[-1])         # 999999
print(500 in r)      # True  —— 支持成员测试

# range 对象只存储 start, stop, step 三个值
# 不管范围多大,内存占用恒定
import sys
print(sys.getsizeof(range(10)))       # 48 字节
print(sys.getsizeof(range(1000000)))  # 48 字节 —— 一样大!

踩坑点: range 对象不支持 + 拼接和 * 重复,这些是 list 的操作。

# ❌ TypeError
range(3) + range(3)

# ✓ 转成 list 或用 itertools.chain
list(range(3)) + list(range(3))  # [0, 1, 2, 0, 1, 2]

4.2 enumerate:带索引遍历

当你需要「同时拿索引和元素」时,enumerate 是 Pythonic 的做法。

# ❌ 不推荐:手动维护索引
i = 0
for fruit in fruits:
    print(i, fruit)
    i += 1

# ❌ 不推荐:用 range(len())
for i in range(len(fruits)):
    print(i, fruits[i])

# ✓ 推荐:enumerate
for index, fruit in enumerate(fruits):
    print(index, fruit)

# enumerate 还能指定起始索引
for index, fruit in enumerate(fruits, start=1):
    print(f"第{index}个:{fruit}")

enumerate 底层实现

# enumerate 的等价实现
def my_enumerate(iterable, start=0):
    n = start
    for elem in iterable:
        yield n, elem
        n += 1

# 它返回的是 enumerate 对象,不是列表
e = enumerate(["a", "b", "c"])
print(type(e))  # <class 'enumerate'>
print(list(e))  # [(0, 'a'), (1, 'b'), (2, 'c')]

4.3 zip:并行迭代多个序列

zip 把多个可迭代对象「拉链式」合并,每次取各序列的一个元素组成元组。

names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["北京", "上海", "深圳"]

# 基本用法:两两配对
for name, age in zip(names, ages):
    print(f"{name} 今年 {age} 岁")

# 多个序列并行
for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 住在{city}")

# 输出:
# Alice, 25岁, 住在北京
# Bob, 30岁, 住在上海
# Charlie, 35岁, 住在深圳

zip 的「木桶效应」

# zip 以最短的那个序列为准
a = [1, 2, 3, 4, 5]
b = ["a", "b", "c"]
print(list(zip(a, b)))  # [(1, 'a'), (2, 'b'), (3, 'c')]  —— 4和5丢了!

# 如果要保留所有元素,用 itertools.zip_longest
from itertools import zip_longest
print(list(zip_longest(a, b, fillvalue="?")))
# [(1, 'a'), (2, 'b'), (3, 'c'), (4, '?'), (5, '?')]

zip 的妙用:矩阵转置

# 经典技巧:二维矩阵转置
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

transposed = list(zip(*matrix))
print(transposed)  # [(1, 4, 7), (2, 5, 8), (3, 6, 9)]

# *matrix 展开 = zip([1,2,3], [4,5,6], [7,8,9])
# zip 从每个子列表取第1个元素组成第1个元组,以此类推

zip 创建字典

keys = ["name", "age", "city"]
values = ["yance", 30, "深圳"]

# Pythonic 的字典构造法
person = dict(zip(keys, values))
print(person)  # {'name': 'yance', 'age': 30, 'city': '深圳'}

Python 3 的坑: Python 3 的 zip 返回的是迭代器(惰性的),只能遍历一次。Python 2 返回的是列表。

z = zip([1, 2], ["a", "b"])
print(list(z))  # [(1, 'a'), (2, 'b')]
print(list(z))  # [] —— 迭代器已经耗尽了!

5. break / continue / pass 与循环控制

5.1 三者对比

关键字作用影响范围
break跳出当前循环(彻底结束循环)最近的 for / while
continue跳过本次迭代剩余代码,进入下一次最近的 for / while
pass什么都不做(占位符)无影响

5.2 break:跳出循环

# 找到第一个能被7整除的数
for n in range(1, 100):
    if n % 7 == 0:
        print(f"找到了:{n}")
        break  # 找到就停,不继续了

# 输出:找到了:7

break 只跳一层

# 嵌套循环中,break 只跳出最内层
for i in range(3):
    for j in range(3):
        if j == 1:
            break  # 只跳出内层 for
        print(f"i={i}, j={j}")

# 输出:
# i=0, j=0
# i=1, j=0
# i=2, j=0

跳出多层循环的技巧

# 方法1:标志变量
found = False
for i in range(5):
    for j in range(5):
        if i * j == 6:
            found = True
            break  # 跳出内层
    if found:
        break  # 跳出外层

# 方法2:for...else + break(更 Pythonic)
for i in range(5):
    for j in range(5):
        if i * j == 6:
            print(f"找到:i={i}, j={j}")
            break
    else:
        continue  # 内层没 break,继续外层
    break  # 内层 break 了,也跳出外层

# 方法3:封装成函数 + return(最推荐)
def find_pair():
    for i in range(5):
        for j in range(5):
            if i * j == 6:
                return i, j
    return None

result = find_pair()

5.3 continue:跳过本次

# 打印所有奇数
for n in range(1, 10):
    if n % 2 == 0:
        continue  # 偶数跳过,不执行后面的 print
    print(n, end=" ")  # 1 3 5 7 9

# 过滤列表中的空字符串
data = ["hello", "", "world", None, "python", ""]
for item in data:
    if not item:  # 空字符串和 None 都是假值
        continue
    print(item)

# 输出:
# hello
# world
# python

踩坑点: continuewhile 循环中要特别小心——确保它在条件变量更新之前不会跳过更新。

# ❌ 死循环!continue 跳过了 count += 1
count = 0
while count < 5:
    if count == 2:
        continue  # count 永远停在 2...
    print(count)
    count += 1

# ✓ 正确:把更新放在 continue 之前
count = 0
while count < 5:
    if count != 2:
        print(count)
    count += 1  # 更新一定执行

5.4 pass:占位符

pass 是一个空操作——什么都不做。它存在的唯一意义是语法占位,因为 Python 的代码块不能为空。

# 1. 空函数/类的占位
def not_implemented_yet():
    pass  # 先占个位,以后再写

class EmptyClass:
    pass

# 2. 条件分支的占位
if debug_mode:
    pass  # TODO: 加调试逻辑
else:
    do_something()

# 3. 在 try-except 中忽略异常
try:
    risky_operation()
except SomeError:
    pass  # 故意忽略这个异常

pass vs … (Ellipsis)

# Python 3 中,... 也能做占位符
def stub():
    ...

class Empty:
    ...

# ... 和 pass 效果一样,但 ... 是一个真正的对象(Ellipsis)
# pass 是语句,... 是表达式
# 类型标注中 ... 有特殊含义
def callback() -> ...:
    ...

最佳实践: except: pass 是 Python 中最被诟病的模式之一(被称为「吞掉异常」)。如果你真的要忽略异常,至少记录一下日志:

# ❌ 吞异常,出了问题无从排查
try:
    do_something()
except Exception:
    pass

# ✓ 至少记录一下
import logging
try:
    do_something()
except Exception as e:
    logging.warning(f"操作失败: {e}")

6. match-case 模式匹配(Python 3.10+)

6.1 介绍

Python 3.10 引入了 match-case,这不是简单的 switch-case,而是结构化模式匹配(Structural Pattern Matching)——源自函数式语言(如 Haskell、Scala、Rust)的强大特性。

# 基本语法
match subject:
    case pattern_1:
        # 匹配 pattern_1 时执行
        pass
    case pattern_2:
        # 匹配 pattern_2 时执行
        pass
    case _:
        # 都不匹配时执行(_ 是通配符)
        pass

6.2 各种模式

字面量模式

def http_status(code: int) -> str:
    match code:
        case 200:
            return "OK"
        case 404:
            return "Not Found"
        case 500:
            return "Internal Server Error"
        case _:
            return "Unknown"

print(http_status(200))  # OK
print(http_status(404))  # Not Found

变量绑定模式

# 匹配的值会绑定到变量上
point = (3, 4)

match point:
    case (0, 0):
        print("原点")
    case (0, y):
        print(f"在Y轴上,y={y}")  # y 绑定为 4
    case (x, 0):
        print(f"在X轴上,x={x}")
    case (x, y):
        print(f"坐标:({x}, {y})")  # x=3, y=4

类模式

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

def describe(point: Point) -> str:
    match point:
        case Point(x=0, y=0):
            return "原点"
        case Point(x=0, y=y):
            return f"Y轴上,y={y}"
        case Point(x=x, y=0):
            return f"X轴上,x={x}"
        case Point(x=x, y=y):
            return f"普通点({x}, {y})"

print(describe(Point(3, 4)))  # 普通点(3, 4)

序列模式

def process_command(cmd: list) -> str:
    match cmd:
        case ["quit"]:
            return "退出程序"
        case ["help"]:
            return "显示帮助"
        case ["go", direction]:
            return f"向{direction}移动"
        case ["go", direction, distance]:
            return f"向{direction}移动{distance}步"
        case ["look", *rest]:
            return f"查看:{rest}"  # *rest 捕获剩余元素
        case _:
            return "未知命令"

print(process_command(["go", "north"]))       # 向north移动
print(process_command(["go", "north", 5]))     # 向north移动5步
print(process_command(["look", "around"]))     # 查看:['around']

映射(字典)模式

def handle_event(event: dict) -> str:
    match event:
        case {"type": "click", "x": x, "y": y}:
            return f"点击坐标({x}, {y})"
        case {"type": "keypress", "key": key}:
            return f"按键:{key}"
        case {"type": "scroll", "delta": delta}:
            return f"滚动:{delta}"
        case _:
            return "未知事件"

print(handle_event({"type": "click", "x": 100, "y": 200}))
# 点击坐标(100, 200)

守卫(Guard)模式

def classify_number(n: int) -> str:
    match n:
        case n if n < 0:
            return "负数"
        case n if n == 0:
            return "零"
        case n if n < 10:
            return "小正数"
        case n if n < 100:
            return "中等正数"
        case _:
            return "大正数"

print(classify_number(-5))   # 负数
print(classify_number(0))    # 零
print(classify_number(7))    # 小正数
print(classify_number(50))   # 中等正数
print(classify_number(999))  # 大正数

or 模式

def day_type(day: str) -> str:
    match day.lower():
        case "saturday" | "sunday":
            return "周末"
        case "monday" | "tuesday" | "wednesday" | "thursday" | "friday":
            return "工作日"
        case _:
            return "无效输入"

6.3 match-case vs if-elif-else 对比

# 传统 if-elif 写法
def handle_http(method, path):
    if method == "GET" and path == "/users":
        return "获取用户列表"
    elif method == "GET" and path.startswith("/users/"):
        user_id = path.split("/")[-1]
        return f"获取用户{user_id}"
    elif method == "POST" and path == "/users":
        return "创建用户"
    else:
        return "未知路由"

# match-case 写法(更清晰)
def handle_http_v2(method, path):
    parts = path.strip("/").split("/")
    match (method, parts):
        case ("GET", ["users"]):
            return "获取用户列表"
        case ("GET", ["users", user_id]):
            return f"获取用户{user_id}"
        case ("POST", ["users"]):
            return "创建用户"
        case _:
            return "未知路由"

踩坑点: match-case 中的变量名如果和已有变量重名,会被当作新的绑定模式,而不是值比较!

status = 200

# ❌ 这不是比较 status == 200
match response:
    case status:  # 这是变量绑定!永远匹配
        print(f"绑定了: {status}")  # status 被重新赋值为 response 的值

# ✓ 要做值比较,用字面量或加了点号的变量
match response:
    case 200:
        print("OK")
    case _:  # 通配符
        print("其他")

7. 常见陷阱与最佳实践

7.1 陷阱清单

陷阱1:在循环中修改正在遍历的列表

# ❌ 边遍历边删除,会跳过元素
nums = [1, 2, 2, 3, 4, 4, 5]
for n in nums:
    if n % 2 == 0:
        nums.remove(n)
print(nums)  # [1, 2, 3, 4, 5]  —— 没删干净!

# ✓ 方法1:遍历副本
for n in nums[:]:  # nums[:] 创建副本
    if n % 2 == 0:
        nums.remove(n)

# ✓ 方法2:列表推导式(更 Pythonic)
nums = [n for n in nums if n % 2 != 0]

# ✓ 方法3:filter
nums = list(filter(lambda n: n % 2 != 0, nums))

陷阱2:可变默认参数与循环

# ❌ 默认参数在函数定义时只创建一次
def add_item(item, lst=[]):  # lst 在多次调用间共享!
    lst.append(item)
    return lst

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2]  —— 不是 [2]!

# ✓ 用 None 做默认值
def add_item(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

陷阱3:浮点数做循环条件

# ❌ 浮点精度问题可能导致意外行为
i = 0.0
while i != 1.0:  # 可能永远不等!
    i += 0.1
    print(i)
    if i > 2:  # 加个安全阀
        break

# ✓ 用整数范围 + 缩放
for i in range(11):
    val = i / 10.0
    print(val)

陷阱4:无限循环耗尽资源

# ❌ 忘记更新条件
while True:
    response = fetch_data()
    if response is None:
        break
    process(response)
    # 如果 fetch_data 永远不返回 None...死循环

# ✓ 加超时/最大重试限制
max_retries = 100
retry_count = 0
while retry_count < max_retries:
    response = fetch_data()
    if response is None:
        break
    process(response)
    retry_count += 1

7.2 最佳实践

实践1:用列表推导式替代简单循环

# ❌ 传统写法
squares = []
for i in range(10):
    squares.append(i ** 2)

# ✓ 列表推导式
squares = [i ** 2 for i in range(10)]

# 带条件过滤
even_squares = [i ** 2 for i in range(10) if i % 2 == 0]

实践2:用 any() / all() 替代显式循环

# ❌ 显式循环找满足条件的元素
def has_negative(nums):
    for n in nums:
        if n < 0:
            return True
    return False

# ✓ any() 一行搞定
def has_negative(nums):
    return any(n < 0 for n in nums)

# all():所有元素都满足条件
all_positive = all(n > 0 for n in nums)

实践3:循环中避免重复计算

# ❌ 每次循环都调用 len()
for i in range(len(data)):
    process(data[i], len(data))  # len(data) 每次都算

# ✓ 缓存长度
n = len(data)
for i in range(n):
    process(data[i], n)

实践4:用字典替代冗长的 if-elif 链

# ❌ 冗长的 if-elif
def calculate(a, b, op):
    if op == "+":
        return a + b
    elif op == "-":
        return a - b
    elif op == "*":
        return a * b
    elif op == "/":
        return a / b
    else:
        raise ValueError(f"未知运算符: {op}")

# ✓ 字典分发(策略模式)
import operator
ops = {
    "+": operator.add,
    "-": operator.sub,
    "*": operator.mul,
    "/": operator.truediv,
}

def calculate(a, b, op):
    if op not in ops:
        raise ValueError(f"未知运算符: {op}")
    return ops[op](a, b)

8. 实操 Demo

8.1 猜数字游戏

"""
猜数字游戏
- 电脑随机生成 1-100 的数字
- 玩家输入猜测,电脑提示「大了」或「小了」
- 限制最多 7 次机会(二分法理论最优)
- 支持「放弃」提前退出
"""
import random


def guess_number_game() -> None:
    target = random.randint(1, 100)
    max_attempts = 7
    print("=" * 40)
    print("🎮 猜数字游戏(1-100)")
    print(f"你有 {max_attempts} 次机会,输入 'quit' 放弃")
    print("=" * 40)

    for attempt in range(1, max_attempts + 1):
        user_input = input(f"第 {attempt}/{max_attempts} 次猜测:").strip()

        # 处理退出
        if user_input.lower() in ("quit", "exit", "q"):
            print(f"你放弃了!答案是 {target}")
            return

        # 处理非数字输入
        if not user_input.isdigit():
            print("⚠️ 请输入数字!")
            continue  # 不消耗次数(视规则而定)

        guess = int(user_input)

        # 范围检查
        if not (1 <= guess <= 100):
            print("⚠️ 请输入 1-100 之间的数字!")
            continue

        # 比较
        if guess == target:
            print(f"🎉 恭喜!{attempt} 次猜中!")
            return
        elif guess < target:
            print("📈 小了!")
        else:
            print("📉 大了!")

    # 循环正常结束(次数用完没猜中)
    else:
        print(f"💀 机会用完!答案是 {target}")


# 运行游戏
if __name__ == "__main__":
    guess_number_game()

运行效果:

========================================
🎮 猜数字游戏(1-100)
你有 7 次机会,输入 'quit' 放弃
========================================
第 1/7 次猜测:50
📈 小了!
第 2/7 次猜测:75
📉 大了!
第 3/7 次猜测:62
📈 小了!
第 4/7 次猜测:68
📉 大了!
第 5/7 次猜测:65
🎉 恭喜!5 次猜中!

8.2 简易计算器

"""
简易计算器
- 支持加减乘除、取余、幂运算
- 支持连续计算
- 输入 'quit' 退出
- 完整的错误处理
"""
import operator
import sys


# 运算符映射表
OPERATIONS = {
    "+": (operator.add, "加法"),
    "-": (operator.sub, "减法"),
    "*": (operator.mul, "乘法"),
    "/": (operator.truediv, "除法"),
    "//": (operator.floordiv, "整除"),
    "%": (operator.mod, "取余"),
    "**": (operator.pow, "幂运算"),
}


def get_number(prompt: str) -> float | None:
    """安全地获取数字输入,返回 None 表示退出"""
    while True:
        raw = input(prompt).strip()
        if raw.lower() in ("quit", "exit", "q"):
            return None
        try:
            return float(raw)
        except ValueError:
            print("⚠️ 输入无效,请重新输入数字!")


def get_operator() -> str | None:
    """获取运算符输入"""
    ops_display = " / ".join(OPERATIONS.keys())
    while True:
        raw = input(f"选择运算符 ({ops_display}):").strip()
        if raw.lower() in ("quit", "exit", "q"):
            return None
        if raw in OPERATIONS:
            return raw
        print("⚠️ 无效运算符,请重新输入!")


def calculate(a: float, op: str, b: float) -> float:
    """执行计算"""
    func, _ = OPERATIONS[op]
    return func(a, b)


def calculator() -> None:
    print("=" * 50)
    print("🧮 简易计算器")
    print("输入 'quit' 随时退出")
    print("=" * 50)

    while True:
        # 获取第一个操作数
        a = get_number("请输入第一个数:")
        if a is None:
            break

        # 获取运算符
        op = get_operator()
        if op is None:
            break

        # 获取第二个操作数
        b = get_number("请输入第二个数:")
        if b is None:
            break

        # 执行计算(带异常处理)
        try:
            result = calculate(a, op, b)
            op_name = OPERATIONS[op][1]
            print(f"\n✅ 结果:{a} {op} {b} = {result}\n")

            # 特殊情况提示
            if op == "/" and b == 0:
                print("(除以零会产生 inf)")
            elif op == "//" and b == 0:
                print("(整除零会抛异常,已被捕获)")

        except ZeroDivisionError:
            print("\n❌ 错误:除数不能为零!\n")
        except OverflowError:
            print("\n❌ 错误:结果溢出!\n")
        except Exception as e:
            print(f"\n❌ 未知错误:{e}\n")

    print("感谢使用,再见!👋")


# 运行计算器
if __name__ == "__main__":
    calculator()

运行效果:

==================================================
🧮 简易计算器
输入 'quit' 随时退出
==================================================
请输入第一个数:10
选择运算符 (+ / - / * / / / // / % / **):**
请输入第二个数:3

✅ 结果:10.0 ** 3.0 = 1000.0

请输入第一个数:100
选择运算符 (+ / - / * / / / // / % / **):/
请输入第二个数:0

❌ 错误:除数不能为零!

请输入第一个数:quit
感谢使用,再见!👋

9. 总结

9.1 知识图谱

流程控制
├── 条件分支
│   ├── if / elif / else          # 基本条件判断
│   ├── 三元表达式                  # value if cond else value
│   ├── and / or / not            # 逻辑组合 + 短路求值
│   └── match-case (3.10+)        # 结构化模式匹配
├── 循环
│   ├── for                       # 遍历可迭代对象
│   ├── while                     # 条件驱动循环
│   └── else 子句                  # 循环正常结束时执行
├── 迭代工具
│   ├── range                     # 惰性整数序列
│   ├── enumerate                 # 带索引遍历
│   └── zip                       # 并行迭代
├── 循环控制
│   ├── break                     # 跳出循环
│   ├── continue                  # 跳过本次
│   └── pass                      # 空操作占位
└── 最佳实践
    ├── 列表推导式替代简单循环
    ├── any() / all() 替代显式查找
    ├── 字典分发替代 if-elif 链
    └── 避免在循环中修改遍历对象

9.2 速查表

场景推荐示例
简单二选一三元表达式x if cond else y
多分支if-elif-else成绩等级判定
遍历序列forfor item in list
不知道次数while读取直到 EOF
带索引遍历enumeratefor i, v in enumerate(lst)
多序列并行zipfor a, b in zip(l1, l2)
复杂结构匹配match-case解析命令/事件
查找元素any()any(x > 0 for x in lst)
过滤+变换列表推导式[f(x) for x in lst if cond]

9.3 C++ 程序员的 Python 流程控制速记

C++Python备注
if (x) {}if x:不用括号,靠缩进
switch-casematch-case (3.10+) 或 elif3.10 前没有 switch
for (int i=0; i<n; i++)for i in range(n):基于迭代器
for (auto& x : container)for x in container:天然支持
while (x)while x:一样
break / continuebreak / continue一样
{} 空代码块passPython 代码块不能为空
#define MAX 100MAX = 100不用预处理器
goto❌ 不存在用函数 + return 替代

以上就是一文详解Python的流程控制if/for/while的详细内容,更多关于Python流程控制if/for/while的资料请关注脚本之家其它相关文章!

相关文章

  • django 2.0更新的10条注意事项总结

    django 2.0更新的10条注意事项总结

    Django 是 Python Web 开发最常用的框架之一,跟进它的最新变化绝对是必须的。下面这篇文章主要给大家介绍了关于django 2.0更新的10条注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2018-01-01
  • python 中的 super详解

    python 中的 super详解

    这篇文章主要介绍了python 中的 super,提到 super,最直接的想法就是它代表了父类,替父类执行某些方法,但是理解也仅止步于此,下面对 super 做进一步理解,需要的朋友可以参考下
    2022-08-08
  • Python接口自动化之浅析requests模块post请求

    Python接口自动化之浅析requests模块post请求

    这篇文章Python接口自动化之浅析requests模块post请求,以下主要介绍requests模块中的post请求的使用,post源码,data、json参数应用场景及实战
    2021-08-08
  • VSCode设置类似Pycharm控制台运行Python显示中间变量的步骤

    VSCode设置类似Pycharm控制台运行Python显示中间变量的步骤

    这篇文章主要介绍了如何在VSCode中设置调试功能,以实现类似于Pycharm在控制台输出中间变量的功能,文中通过图文介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • 如何利用opencv对拍摄图片进行文字识别

    如何利用opencv对拍摄图片进行文字识别

    在有些工程中有时候我们需要对图片文字识别,下面这篇文章主要给大家介绍了关于如何利用opencv对拍摄图片进行文字识别的相关资料,文中通过代码示例介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • python写日志文件操作类与应用示例

    python写日志文件操作类与应用示例

    这篇文章主要介绍了python写日志文件操作类与应用,结合实例形式分析了Python日志文件操作类的定义与使用相关操作技巧,需要的朋友可以参考下
    2019-07-07
  • Python中zip()函数的简单用法举例

    Python中zip()函数的简单用法举例

    这篇文章主要给大家介绍了关于Python中zip()函数的简单用法,文中通过示例代码介绍的非常详细,对大家学习或者使用Python具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-09-09
  • python实现在线翻译

    python实现在线翻译

    这篇文章主要介绍了python实现在线翻译,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • Python参数传递中双星号(**)和单星号(*)是作用

    Python参数传递中双星号(**)和单星号(*)是作用

    双星号(**)和单星号(*)在参数传递中扮演着关键角色,本文主要介绍了Python参数传递中双星号(**)和单星号(*)是作用,具有一定的参考价值,感兴趣的可以了解一下
    2024-05-05
  • python 划分数据集为训练集和测试集的方法

    python 划分数据集为训练集和测试集的方法

    今天小编就为大家分享一篇python 划分数据集为训练集和测试集的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12

最新评论