Python 控制流

要点

推导式是建立新容器的表达式,普通循环更适合多步骤副作用。生成器表达式则延迟生产,不是另一种已经填满的列表。

1. 条件分支:Python 的真值美学

score = 87

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"          # 注意 elif 而非 else if
else:
    grade = "C"

1. 三元表达式:值在前,条件在后
label = "及格" if score >= 60 else "不及格"

1. 链式比较,数学式写法
if 0 <= score <= 100:
    print("有效分数")

match-case(3.10+)处理多分支结构与解构:

def handle(command: str) -> str:
    match command.split():
        case ["add" | "new", arg]:     # 或模式
            return f"添加 {arg}"
        case ["rm", *targets]:         # 序列解构模式
            return f"删除 {len(targets)} 项"
        case _:
            return "未知命令"

⚠️ case _ 是通配符,必须放最后;匹配字面量直接写值,匹配变量会被当作捕获名——要用点号访问的常量(如 Status.OK)才按值匹配。

def classify(command):
    match command.split():
        case ["add", name] if name:
            return f"add:{name}"
        case ["quit"]:
            return "quit"
        case _:
            return "unknown"

found = None
for value in [0, -1, 4]:
    if value > 0:
        found = value
        break
else:
    found = "missing"

assert (classify("add Ada"), classify("quit"), classify("add"), found) == ("add:Ada", "quit", "unknown", 4)
print("python-keywords: match case guard; for else; break")

该程序从正文原样提取并运行 match、case、if、for、break、else 与 return。 它只验证三条具体控制流路径;模式匹配的类模式、映射模式和异常传播需要另建输入验证。


2. for 循环:迭代即遍历

Python 的 for 遍历可迭代对象,不是下标:

langs = ["python", "go", "rust"]

for lang in langs:                  # 直接遍历元素
    print(lang)

for i, lang in enumerate(langs, start=1):   # 需要下标时
    print(f"{i}. {lang}")

for cn, en in zip(["一", "二"], [1, 2]):     # 并行遍历
    print(cn, en)

for k, v in {"py": 1991, "go": 2009}.items():  # 遍历字典
    print(k, v)

range 与循环控制:

for i in range(3):          # 0, 1, 2(含头不含尾)
    ...

for i in range(10, 0, -2):  # 10, 8, 6, 4, 2
    ...

while True:                 # while 适合"不确定次数"的场景
    cmd = input("> ")
    if cmd == "quit":
        break               # 跳出循环
    if not cmd:
        continue            # 跳过本轮
    print(cmd)

for-else:循环未被 break 打断时执行 else,常用于搜索:

for item in items:
    if item == target:
        print("找到了")
        break
else:
    print("没找到")          # 没被 break 才执行

💡 优先考虑”遍历元素”而非”遍历下标再取元素”。需要下标就用 enumerate,这正是 Python 惯用法与 C 风格循环的分水岭。


3. 推导式:Python 的标志表达力

推导式(comprehension)把”建列表的循环”压缩成一行;其性能常常不错,但是否更快取决于工作量、解释器和等价循环的具体写法:

nums = [1, 2, 3, 4, 5, 6]

1. 列表推导式:[表达式 for 变量 in 可迭代 if 条件]
squares = [n * n for n in nums]                 # [1, 4, 9, 16, 25, 36]
evens = [n for n in nums if n % 2 == 0]         # [2, 4, 6]
matrix_flat = [x for row in [[1, 2], [3, 4]] for x in row]   # [1, 2, 3, 4]

1. 字典推导式
len_map = {w: len(w) for w in ["py", "go"]}     # {'py': 2, 'go': 2}
rev = {v: k for k, v in len_map.items()}        # 键值互换

1. 集合推导式
unique_len = {len(w) for w in ["py", "go", "rust"]}   # {2, 4}

1. 生成器表达式:圆括号,惰性求值,省内存
total = sum(n * n for n in range(1_000_000))    # 不建中间列表

⚠️ 推导式超过两层 for 或两个 if 就该换回普通循环——可读性优先,一行不是目的。

📖 四种推导式的语法对照、条件/嵌套写法与生成器惰性语义,见 推导式速查。


4. 推导式实战:数据清洗三例

# 例1:清洗用户输入
raw = ["  Ada ", "", "BOB", None, "cleo"]
names = [s.strip().title() for s in raw if s]        # ['Ada', 'Bob', 'Cleo']

1. 例2:条件表达式做分支映射
grades = {n: ("pass" if s >= 60 else "fail") for n, s in {"a": 70, "b": 50}.items()}

1. 例3:展平嵌套 JSON 字段
records = [{"tags": ["web", "api"]}, {"tags": ["db"]}]
all_tags = {t for r in records for t in r["tags"]}   # {'web', 'api', 'db'}

any()/all() 配生成器表达式是集合判断的地道写法:

has_admin = any(u["role"] == "admin" for u in users)
all_valid = all(len(u["name"]) > 0 for u in users)

最佳实践

需要索引和值时用 enumerate,需要键值时用 items,可使循环目的更明显;确实要按位置修改或访问邻居时,索引循环仍然合理。推导式适合短的变换,复杂条件和副作用用普通循环更易追踪。

生成器避免提前保存所有中间项,但只消费一次且最终聚合仍可能需要内存。for-else 表示循环未被 break 终止,不是“循环条件为假才开始执行”。用找到、未找到和空输入三个例子验证理解。


常见问题

Q1: 推导式和 map/filter 怎么选?

A: 新代码统一用推导式,可读性更好;map/filter 只在读老代码和已有函数可直接复用时考虑。

Q2: match-case 就是 switch 吗?

A: 远不止——它能解构序列、映射,配合守卫 if 子句做结构化匹配,本质是模式匹配而非值跳转。


练习与实践

练习一:单词统计

  1. 给定 text = "the quick the lazy the dog",用推导式统计每个单词出现次数(dict 推导式 + .split())
  2. 用集合推导式输出出现超过一次的单词

练习二:重构为 match-case

  1. 把下面的 if 链改写成 match-case(含序列解构):
if cmd == "add":
    op, *rest = args
elif cmd == "rm":
    targets = args
else:
    ...
  1. 为 add 分支加守卫:args 为空时输出提示

评估标准:两个练习均用推导式/match 完成,单函数不超过 10 行,ruff 通过。


相关文档

  • 📄 异常处理 — 控制流之外的错误流
  • 📄 数据结构速查 — 推导式各目标的完整语法
  • 📄 Python 一行式速查 — 推导式高频模式集
暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇