Skip to content

条件判断与循环 ​

条件判断让程序可以「分岔」,循环让程序可以「重复」。几乎所有的业务逻辑都由这两类语句组合而成:校验参数、按状态分支、遍历数据、累积结果。本节将系统讲解 if 分支、for / while 循环、break / continue / else,以及循环与条件配合的常见模式。

前置知识

阅读本节前,建议先了解:列表快速上手,熟悉序列的遍历方式。

基础概念 ​

Python 用缩进(Indentation)表示代码块,而不是花括号。真值判断(Truthiness) 是本节的核心:if 后面跟的不是布尔值,而是任意对象——Python 会按真值规则隐式转换。

值真值
0、0.0、0j假
""、[]、()、{}、set()假
None、False假
其他非零、非空对象真

可迭代对象(Iterable) 是 for 循环的基础,字符串、列表、元组、字典、文件、生成器都支持迭代。

语法与用法 ​

if / elif / else 与 for 循环的最基本写法:

python
# 最简可运行示例:条件判断
score = 78

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 60:
    grade = "C"
else:
    grade = "D"

print(f"分数 {score} 对应等级 {grade}")

# 最简可运行示例:for 循环
total = 0
for n in range(1, 6):
    total += n
print(f"1 到 5 的和:{total}")
text
分数 78 对应等级 C
1 到 5 的和:15

详细说明 ​

条件判断与比较 ​

if 支持链式比较与逻辑运算符,注意 and / or 的短路求值(Short-circuit Evaluation):

python
age = 25
has_ticket = True

# 链式比较:等价于 18 <= age and age < 60
if 18 <= age < 60:
    print("成人票")

# 逻辑运算符
if age >= 18 and has_ticket:
    print("可以入场")

# 短路求值:or 返回第一个真值,and 返回第一个假值
username = ""
display_name = username or "匿名用户"      # 常用默认值技巧
print(display_name)

config = {"timeout": 0}
timeout = config.get("timeout") or 30       # 注意:0 会被判为假!
print(f"实际超时:{timeout}")               # 结果不是 0,而是 30
text
成人票
可以入场
匿名用户
实际超时:30

用 or 设默认值的陷阱

当合法值可能是 0、""、False 时,x or default 会错误地替换成默认值。此时应显式判断 if x is None:。

真值判断与身份判断 ​

python
items: list[str] = []

# 推荐:直接判断容器是否为空(利用真值规则)
if not items:
    print("列表为空")

# 不推荐:多余地与空容器比较
if items == []:          # 不推荐
    print("列表为空")

# 判断 None 用 is,而不是 ==
value = None
if value is None:
    print("value 尚未赋值")

# 判断成员关系
roles = ["admin", "editor"]
if "admin" in roles:
    print("拥有管理员权限")
text
列表为空
value 尚未赋值
拥有管理员权限

for 循环与 range ​

range 生成整数序列,是「计数循环」的首选。它惰性生成,不占内存:

python
# 三种形式
print(list(range(5)))          # 0, 1, 2, 3, 4
print(list(range(2, 6)))       # 2, 3, 4, 5
print(list(range(0, 10, 3)))   # 0, 3, 6, 9

# 倒序
for i in range(5, 0, -1):
    print(i, end=" ")
print()

# 遍历字典
user = {"name": "alice", "age": 30}
for key in user:                       # 默认遍历键
    print(key)

for key, value in user.items():        # 同时遍历键值
    print(f"{key} = {value}")

# 并行遍历多个序列(推荐用 zip,而不是索引)
names = ["alice", "bob", "cathy"]
scores = [90, 85, 92]
for name, score in zip(names, scores):
    print(f"{name:<8}{score}")
text
[0, 1, 2, 3, 4]
[2, 3, 4, 5]
[0, 3, 6, 9]
5 4 3 2 1 
name
age
name = alice
age = 30
alice   90
bob     85
cathy   92

while 循环 ​

while 适用于「循环次数不确定」的场景,如等待条件满足、读取输入直到退出:

python
# 用 while 实现重试逻辑
import random

random.seed(42)
attempts = 0
max_attempts = 5

while attempts < max_attempts:
    attempts += 1
    if random.random() < 0.5:          # 模拟一次成功率为 50% 的操作
        print(f"第 {attempts} 次尝试成功")
        break
else:
    # while 的 else 分支:循环未被 break 时执行
    print(f"重试 {max_attempts} 次仍失败,终止")

# 无限循环 + 手动退出条件
countdown = 3
while True:
    print(f"倒计时 {countdown}")
    countdown -= 1
    if countdown == 0:
        print("发射!")
        break
text
第 1 次尝试成功
倒计时 3
倒计时 2
倒计时 1
发射!

for / while 的 else 子句

else 在循环正常结束(未被 break)时执行,常用于「查找未命中」的场景。它与 if 的 else 语义完全不同,容易被误解。

break、continue 与循环控制 ​

python
# continue:跳过本次迭代
for n in range(1, 8):
    if n % 2 == 0:
        continue                       # 偶数跳过
    print(n, end=" ")
print()

# break:提前结束整个循环
for n in range(1, 100):
    if n * n > 50:
        print(f"第一个平方大于 50 的数是 {n}")
        break

# for-else:查找未命中时提示
target = "python"
languages = ["go", "java", "rust"]
for lang in languages:
    if lang == target:
        print("找到目标语言")
        break
else:
    print(f"列表中不存在 {target}")
text
1 3 5 7 
第一个平方大于 50 的数是 8
列表中不存在 python

嵌套循环与推导式选择 ​

python
# 嵌套循环:打印乘法表(只打印下三角)
for i in range(1, 5):
    for j in range(1, i + 1):
        print(f"{j}x{i}={i * j}", end="\t")
    print()

# 多层循环用 break 只能跳出最内层,需要标志位或封装为函数
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
found = False
for row in matrix:
    for value in row:
        if value == 5:
            found = True
            break
    if found:
        break
print(f"找到 5:{found}")

# 用 any/all + 生成器表达式替代标志位(更 Pythonic)
print("找到 5:", any(5 in row for row in matrix))
text
1x1=1	
1x2=2	2x2=4	
1x3=3	2x3=6	3x3=9	
1x4=4	2x4=8	3x4=12	4x4=16	
找到 5:True
找到 5: True

match 语句 ​

Python 3.10 引入的结构化模式匹配(Structural Pattern Matching),适合替代冗长的 if/elif:

python
# Python 3.10+
def describe_command(command: str) -> str:
    """根据命令字符串返回处理说明"""
    match command.split():
        case ["quit"]:
            return "退出程序"
        case ["go", direction]:
            return f"向 {direction} 前进"
        case ["pick", *items]:
            return f"拾取 {len(items)} 件物品:{', '.join(items)}"
        case ["look"] | ["l"]:
            return "环顾四周"
        case _:                                    # 默认分支
            return "无法识别的命令"

for cmd in ["quit", "go north", "pick sword shield", "l", "dance"]:
    print(f"{cmd!r:24} -> {describe_command(cmd)}")
text
'quit'                   -> 退出程序
'go north'               -> 向 north 前进
'pick sword shield'      -> 拾取 2 件物品:sword, shield
'l'                      -> 环顾四周
'dance'                  -> 无法识别的命令

实战示例 ​

示例一:带校验的多分支业务规则 ​

python
from dataclasses import dataclass

@dataclass
class Order:
    """订单"""
    amount: float
    is_vip: bool
    coupon: float = 0.0

def calc_discount(order: Order) -> tuple[float, str]:
    """计算折扣金额与说明,返回 (折扣额, 说明)"""
    if order.amount <= 0:
        return 0.0, "金额异常,不打折"

    if order.amount >= 1000:
        rate, desc = 0.15, "满 1000 打 85 折"
    elif order.amount >= 500:
        rate, desc = 0.10, "满 500 打 9 折"
    elif order.amount >= 100:
        rate, desc = 0.05, "满 100 打 95 折"
    else:
        rate, desc = 0.0, "未达折扣门槛"

    discount = order.amount * rate

    # 会员额外叠加 5%,但折扣总额不超过订单金额
    if order.is_vip:
        extra = order.amount * 0.05
        discount += extra
        desc += ",会员额外 5%"

    discount = min(discount, order.amount)
    return round(discount, 2), desc

orders = [
    Order(amount=1200.0, is_vip=True),
    Order(amount=300.0, is_vip=False),
    Order(amount=50.0, is_vip=True),
]
for order in orders:
    discount, desc = calc_discount(order)
    final = order.amount - discount
    print(f"原价 {order.amount:>8.2f} 折扣 {discount:>7.2f} 实付 {final:>8.2f}  ({desc})")
text
原价  1200.00 折扣  240.00 实付   960.00  (满 1000 打 85 折,会员额外 5%)
原价   300.00 折扣   15.00 实付   285.00  (满 100 打 95 折)
原价    50.00 折扣    2.50 实付    47.50  (未达折扣门槛,会员额外 5%)

示例二:循环聚合与数据清洗 ​

python
# 原始日志行:时间 级别 消息
raw_logs = [
    "2026-10-08 10:00:01 INFO 服务启动",
    "2026-10-08 10:00:05 ERROR 数据库连接失败",
    "2026-10-08 10:00:06 INFO 重试中",
    "2026-10-08 10:00:07 ERROR 数据库连接失败",
    "2026-10-08 10:00:08 WARN 连接池接近上限",
    "非法日志行",
]

level_count: dict[str, int] = {}
error_lines: list[str] = []

for line in raw_logs:
    parts = line.split(maxsplit=3)
    # 跳过格式不符的行(防御式编程)
    if len(parts) != 4:
        continue

    _, level, message = parts[0], parts[1], parts[3]
    level_count[level] = level_count.get(level, 0) + 1

    if level == "ERROR":
        error_lines.append(message)

print("各级别数量:")
for level, count in sorted(level_count.items()):
    print(f"  {level:<6}{count}")

print(f"\n错误共 {len(error_lines)} 条:")
for msg in error_lines:
    print(f"  - {msg}")

# 用计数器找出出现次数最多的错误
if error_lines:
    top = max(set(error_lines), key=error_lines.count)
    print(f"\n最常见错误:{top}({error_lines.count(top)} 次)")
text
各级别数量:
  ERROR 2
  INFO  2
  WARN  1

错误共 2 条:
  - 数据库连接失败
  - 数据库连接失败

最常见错误:数据库连接失败(2 次)

示例三:循环控制与生成器管道 ​

python
def read_numbers(lines: list[str]) -> list[float]:
    """从文本行中解析数字,跳过无效行"""
    numbers: list[float] = []
    for line in lines:
        line = line.strip()
        if not line or line.startswith("#"):     # 跳过空行与注释
            continue
        try:
            numbers.append(float(line))
        except ValueError:
            print(f"跳过无效行:{line!r}")
    return numbers

raw = ["12.5", "# 这是注释", "", "abc", "7.5", "-3.0", "0"]
values = read_numbers(raw)
print(f"有效数据:{values}")

# 累加正数,遇到连续两个负数时停止
total = 0.0
negative_streak = 0
for value in values:
    if value < 0:
        negative_streak += 1
        if negative_streak >= 2:
            print("连续出现负数,提前结束统计")
            break
        continue
    negative_streak = 0
    total += value

print(f"累计正数和:{total}")
text
跳过无效行:'abc'
有效数据:[12.5, 7.5, -3.0, 0.0]
累计正数和:20.0

注意事项 ​

  • 缩进必须一致:同一代码块混用 Tab 与空格会抛出 TabError,统一用 4 个空格。
  • = 与 == 混淆:if x = 1: 是语法错误;条件判断要用 ==,身份判断用 is。
  • range 右边界不包含:range(5) 生成 0~4,这是最常见的差一错误来源。
  • 不要在遍历列表时增删元素:会跳过元素,应遍历副本或使用推导式重建。
  • or 设默认值会吞掉假值:合法值可能为 0 / "" 时应显式 is None 判断。
  • while 必须有退出条件:忘记更新循环变量会导致死循环。
  • 浮点数不要用 == 比较:0.1 + 0.2 == 0.3 为 False,应使用容差或 Decimal。
  • 循环 else 易被误读:它不是「循环出错时执行」,而是「未被 break 时执行」。
python
# 错误!遍历时修改列表会跳过元素
nums = [1, 2, 3, 4, 5, 6]
for n in nums:
    if n % 2 == 0:
        nums.remove(n)
print(f"错误结果:{nums}")

# 正确:用推导式重建
nums2 = [1, 2, 3, 4, 5, 6]
nums2 = [n for n in nums2 if n % 2 != 0]
print(f"正确结果:{nums2}")
text
错误结果:[1, 3, 5, 6]
正确结果:[1, 3, 5]

最佳实践 ​

  • 用 in 判断成员,用 is 判断 None:if x is None: 比 if x == None: 更准确。
  • 避免三层以上嵌套:用「卫语句(Guard Clause)」提前 return / continue 降低缩进。
  • 计数循环优先 range:不要手动维护 i = 0; i += 1。
  • 并行遍历用 zip:避免用下标同时索引多个列表。
  • 提前计算循环外的不变量:把循环内不变的计算和属性查找提到循环外。
  • 用 enumerate 同时取索引与元素:比 range(len(x)) 更清晰。
  • 善用 any / all / sum:把「循环 + 标志位」写成内置函数表达式。
  • 复杂分支用 match:Python 3.10+ 中,结构化匹配比多层 if/elif 更易读。
python
# 卫语句代替深层嵌套
def process(records: list[dict], min_age: int) -> list[str]:
    """筛选并返回符合条件的人员姓名"""
    result: list[str] = []
    for record in records:
        if not record:                    # 卫语句:提前跳过
            continue
        age = record.get("age")
        if age is None or age < min_age:
            continue
        result.append(record.get("name", "未知"))
    return result

data = [
    {"name": "alice", "age": 30},
    {},
    {"name": "bob", "age": 17},
    {"name": "cathy", "age": 25},
]
print(process(data, min_age=18))
text
['alice', 'cathy']

下一节

继续学习:定义函数

参考链接 ​