# Python 中的循环与条件：for、while、range、enumerate、break、if/elif 和 match/case

URL: https://skillaria.top/zh/guides/python/cikly-python

Python 中的循环用来重复执行操作：for 遍历列表、字符串、字典或 range() 生成的数字，while 则在条件为真时一直执行。break 用于跳出循环，continue 用于跳过本次迭代，enumerate() 提供元素编号。决策由 if/elif/else 条件完成，而 match/case（自 Python 3.10 起）用于按形状拆分数据。

Python 中的循环用来重复执行某个操作：遍历购物清单，处理文件的每一行，或者在用户输入正确的数字之前一直询问。语言中有两种循环——`for` 和 `while`，而在循环内部做决定则依靠 `if/elif/else` 条件以及 `match/case` 语句。下面通过实际示例，逐一讲解每个工具。

## 条件：if、elif、else

条件语句只有在表达式为真时才执行代码块。代码块通过 4 个空格的缩进来标识——Python 中没有花括号，缩进错误会立即导致 `IndentationError`。

```
spent = 4200
limit = 5000

if spent > limit:
    print("已超出限额")
elif spent > limit * 0.8:
    print("剩余预算不足 20%")
else:
    print("一切正常")
```

`elif` 分支从上到下依次检查，只执行第一个满足条件的分支。因此更严格的条件应该放在上面：如果把 `spent > limit * 0.8` 放在第一位，“超出限额”的提示就永远不会出现。

### 什么算作真

条件中不一定要写比较式。假值包括 `False`、`None`、零（`0`、`0.0`）以及空集合：`""`、`[]`、`{}`。其他所有值都是真。因此“列表不为空”的检查可以写得很简短：

```
expenses = []
if not expenses:
    print("暂时没有支出")
```

条件可以用 `and`、`or`、`not` 组合，范围检查则适合写成链式比较：`if 0 < amount <= 100_000:`。对于简短的二选一，还有三元运算符：`status = "很多" if spent > limit else "正常"`。

## for 循环：语法与示例

Python 中的 `for` 不是 C 语言那样的计数器，而是逐个元素的遍历。它依次取出可迭代对象中的每一个元素：列表、字符串、字典、文件或 range。其他语言中的 foreach，就是 Python 中普通的 `for`。

```
expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
    total += amount
print(total)  # 6139
```

for 循环的语法是：`for 变量 in 集合:`，然后是带缩进的代码块。循环结束后，变量会保留最后一个值——有时这很有用，但在大型程序中不应依赖这一点。

### 遍历字符串、列表和字典

字符串逐个字符遍历，列表逐个元素遍历。遍历字典时默认取的是键；要同时获得键和值，使用 `.items()`：

```
by_category = {"餐饮": 3200, "交通": 900, "电影": 600}

for category, amount in by_category.items():
    print(f"{category}: {amount} ₽")
```

如果只需要值，使用 `.values()`。在遍历过程中不能改变字典的大小，否则会得到 `RuntimeError: dictionary changed size during iteration`。如果需要删除元素，请遍历它的副本：`for key in list(d):`。

## range 函数：按数字循环

需要遍历数字时，可以使用 `range()`。它不会在内存中创建列表，而是逐个生成数字，因此 `range(10**9)` 可以瞬间创建。

| 调用 | 生成的数字 |
| --- | --- |

| `range(5)` | 0, 1, 2, 3, 4 |

| `range(2, 6)` | 2, 3, 4, 5 |

| `range(0, 10, 3)` | 0, 3, 6, 9 |

| `range(5, 0, -1)` | 5, 4, 3, 2, 1 |

关键规则：右边界不包含在内。`range(1, 10)` 结束于 9——这是“差一错误”的常见原因。步长可以是负数，但不能为零。

```
for i in range(1, 4):
    print(f"第 {i} 天")
# 第 1 天
# 第 2 天
# 第 3 天
```

## enumerate：循环中的计数器

新手常常写 `for i in range(len(items))` 来获得元素的编号。这样也能工作，但可读性较差。函数 `enumerate()` 会返回“编号、元素”的配对，参数 `start` 决定从哪个数字开始计数：

```
items = ["咖啡", "打车", "午饭"]
for n, item in enumerate(items, start=1):
    print(n, item)
# 1 咖啡
# 2 打车
# 3 午饭
```

要同时遍历两个列表，使用 `zip()`：`for name, price in zip(names, prices):`。它在最短的列表结束时停止；从 Python 3.10 起，可以传入 `strict=True`，这样长度不一致时会报错。

## Python 中的 while 循环

`while` 循环在条件为真时重复执行代码块。当重复次数事先未知时，就使用它：等待正确的输入，读取数据直到结束，或者不断重试直到成功。

```
balance = 10_000
month = 0
while balance > 0:
    balance -= 2_700
    month += 1
print(f"钱够用 {month} 个月。")  # 4
```

主要风险是忘记修改条件中用到的变量，这样循环永远不会结束。如果程序“卡死”了，按 Ctrl+C，Python 会以 `KeyboardInterrupt` 中断执行。

### 无限循环与 do while

有时会有意编写无限循环：`while True:`，再通过 `break` 退出。Python 中没有 `do while` 语句，这种写法就是它的替代：循环体至少执行一次，条件检查放在末尾。

```
while True:
    raw = input("金额：")
    if raw.isdigit():
        amount = int(raw)
        break
    print("请输入整数")
```

for 循环很少会变成无限循环——只有在遍历无限迭代器时才会，例如 `itertools.count()`。

## break 与 continue：跳出循环与跳过迭代

`break` 立即终止循环，程序接着执行循环之后的代码。`continue` 跳过当前迭代的剩余部分，直接进入下一次迭代。

```
expenses = [350, -10, 1200, 0, 99_999, 89]

for amount in expenses:
    if amount  50_000:
        print("金额可疑，停止")
        break             # 跳出循环
    print(amount)
```

上面的代码会输出 350 和 1200，然后打印提示信息——循环永远到不了 89。这两个语句只作用于它们所在的最内层循环。

### 循环的 else

`for` 和 `while` 都有一个不常见的 `else` 分支：只有当循环自然结束、没有被 `break` 中断时才会执行。这在查找时很方便：

```
for amount in expenses:
    if amount > 50_000:
        print("找到了一笔大额支出")
        break
else:
    print("没有大额支出")
```

## 嵌套循环

循环中嵌套循环时，内层循环会在外层的每一次迭代中完整执行一遍。用这种方式遍历表格、矩阵或成对的元素。

```
for row in range(1, 4):
    for col in range(1, 4):
        print(row * col, end="\t")
    print()
```

需要注意两点。第一，运算量增长很快：两层循环各遍历 10 000 个元素，就是 1 亿次操作。第二，`break` 只能跳出内层循环。若要同时结束两层循环，把循环放进函数里，用 `return` 返回——这比使用标志变量更清晰。

## match/case 语句

自 Python 3.10 起，冗长的 `if cmd == ... elif ...` 链可以用 `match` 语句（PEP 634）替代。它不只是 switch：它会把值与模式按结构进行匹配，并同时把各部分拆分到变量中。

```
def parse(text):
    match text.split():
        case ["add", item, amount]:
            return f"添加 {item}: {amount}"
        case ["list"] | ["ls"]:
            return "显示支出"
        case ["quit"]:
            return "退出"
        case _:
            return "未知命令"

print(parse("add 咖啡 250"))  # 添加 咖啡: 250
print(parse("add 咖啡"))      # 未知命令
```

列表模式 `["add", item, amount]` 只会匹配恰好三个元素、且第一个为 `"add"` 的列表。因此没有金额的命令会落入 `_` 分支，它接收所有其他情况。符号 `|` 用来合并多个备选项。

### 字典、类型与守卫条件

字典模式只检查列出的键，多余的键会被忽略。`int(a)` 这样的写法既检查类型，又捕获值；模式后面的 `if` 则增加额外条件（守卫，guard）：

```
match event:
    case {"type": "expense", "amount": int(a)} if a > 10_000:
        print("大额支出", a)
    case {"type": "expense", "amount": int(a)}:
        print("支出", a)
```

### match 的主要陷阱

`case` 中单独的名字是捕获变量，而不是与变量比较。`case limit:` 会匹配任何值，并把它写入 `limit`。要和常量比较，应使用带点的名字，例如 `case Color.RED:`，或使用字面量。

自 3.10 起，match 的语法几乎没有变化。Python 3.15 修正了一处小的不对称：过去字面量模式中只允许数字前面带负号，现在也可以写 `case +1:`。在较旧的版本中，这样的代码会产生语法错误。

## 循环中的常见错误

- **在遍历时修改列表。** 在 `for` 中删除元素会跳过相邻的元素。更好的做法是生成一个新列表：`clean = [x for x in items if x > 0]`。
- **range 的边界。** `range(1, n)` 不包含 `n`。
- **while 中忘记修改条件**——导致无限循环。
- **在循环中用 += 拼接字符串**，数据量大时比 `"".join(parts)` 慢。
- **把赋值当作比较**：`if x = 5` 是语法错误，比较应写作 `==`。

## 循环练习题

1. 计算一个支出列表的总和与平均值，跳过负数。
2. 用嵌套循环输出 1–9 的乘法表。
3. 不断询问用户输入数字，直到输入空字符串，然后输出最大值。
4. 在列表中找出第一个大于 1000 的数；如果没有，给出提示（使用 `for ... else`）。
5. 用 `match` 解析命令 `add`、`del`、`list`。

## 小结

Python 的循环归结为两种结构：`for` 遍历集合或 `range()`，`while` 在条件成立期间持续执行。`break` 和 `continue` 控制循环的流程，`enumerate()` 和 `zip()` 省去手动计数，而 `if/elif/else` 和 `match/case` 负责做出决定。课程中的支出记录器项目会在实践中用到所有这些工具。

## FAQ

**for 和 while 在 Python 中有什么区别？**

for 遍历现成的序列，自己知道何时结束；while 只要条件为真就重复执行。如果重复次数已知或有集合可遍历，用 for；如果在等待某个事件，用 while。

**如何倒序遍历循环？**

对集合使用 reversed(items)，对数字使用 range(n - 1, -1, -1)。reversed 不会复制列表，而是从末尾开始遍历。

**Python 中有 switch 吗？**

没有单独的 switch，它的作用由 if/elif 链以及 Python 3.10 引入的 match/case 实现。match 的功能更强：可以按结构拆分列表和字典，并捕获值。

**循环和列表推导式哪个更快？**

形如 [x * 2 for x in items] 的列表推导式通常比等价的 append 循环略快，而且更简短。涉及多个条件的复杂逻辑，用普通循环更易读。

**如何一次跳出两层嵌套循环？**

break 只跳出内层循环。最简单的办法是把循环放进一个函数中，然后用 return 退出。


---
Source: Skillaria.Top (https://skillaria.top)
