第 4 章 条件控制与循环

731 阅读14分钟

在 Python 中,条件控制与循环是构建程序逻辑流程的核心机制。条件控制让程序能够根据不同情况做出决策,循环则使程序能够重复执行特定操作。从数据过滤到流程自动化,从用户交互到系统监控,几乎所有实用程序都依赖这些结构实现核心功能。本章系统讲解 Python 条件判断语句、循环结构及相关控制工具,结合工程实践解析其应用场景与优化技巧,帮助读者建立清晰的程序流程控制思维,为编写高效、可读的代码奠定基础。

4.1 条件语句

条件语句是程序实现 "决策能力" 的基础,通过判断条件的真假来选择执行不同的代码分支。Python 提供简洁直观的条件判断语法,无需冗余的括号或关键字,使逻辑表达更加清晰。

4.1.1 基本条件结构

Python 支持三种基本条件结构,分别适用于不同的判断场景:

结构形式适用场景语法示例
if 语句单一条件判断if condition:statement
if-else 语句二选一判断if condition:statement1 else:statement2
if-elif-else 语句多条件分支判断if condition1:statement1 elif condition2:statement2 else:statement3

if 语句示例

# 场景:权限验证
user_role = "editor"
if user_role == "admin":
    print("授予管理员权限")

if-else 语句示例

# 场景:年龄判断
age = 20
if age >= 18:
    print("已成年")
else:
    print("未成年")

if-elif-else 语句示例

# 场景:成绩评级
score = 85
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 60:
    grade = "C"
else:
    grade = "D"
print(f"成绩评级:{grade}")  # 输出:成绩评级:B

📌 重点提示:条件语句必须使用冒号 : 结束条件表达式,且缩进(通常为 4 个空格)是区分代码块的唯一方式,而非其他语言常用的花括号 {}

4.1.2 条件表达式

条件表达式是返回布尔值(True 或 False)的表达式,是条件语句的核心判断依据。Python 支持多种形式的条件表达式:

  1. 比较运算表达式

    x = 10
    print(x > 5)      # True
    print(x == 10)    # True
    print(x != 10)    # False
    
  2. 逻辑运算表达式

    a, b = 5, 15
    print(a > 0 and b < 20)  # True
    print(a > 10 or b > 10)  # True
    print(not a > b)         # True
    
  3. 成员运算表达式

    fruits = ["apple", "banana"]
    print("apple" in fruits)     # True
    print("orange" not in fruits) # True
    
  4. 身份运算表达式

    x = None
    print(x is None)  # True
    

示例:复合条件判断

# 场景:用户登录验证
username = "alice"
password = "secure123"
is_active = True

# 复合条件:用户名密码正确且账号激活
if username == "alice" and password == "secure123" and is_active:
    print("登录成功")
else:
    print("登录失败")

4.1.3 条件语句的嵌套与组合

复杂逻辑场景需要多个条件语句的嵌套或组合使用,形成多层判断结构:

嵌套条件示例

# 场景:订单处理
order_amount = 150
has_coupon = True

if order_amount > 100:
    print("满足优惠条件")
    if has_coupon:
        print("使用优惠券,额外减免20元")
    else:
        print("无优惠券,享受9折优惠")
else:
    print("不满足优惠条件")

条件组合示例

# 场景:电影票价计算
age = 25
is_student = True

# 组合条件判断不同票价
if age < 12:
    price = 30
elif age >= 60:
    price = 40
elif is_student:
    price = 50
else:
    price = 80

print(f"票价:{price}元")  # 输出:票价:50元

📌 最佳实践:嵌套条件不宜超过 3 层,过多的嵌套会降低代码可读性。复杂逻辑应考虑拆分为多个函数,或使用逻辑运算符组合条件。

4.1.4 三元条件表达式

Python 提供三元条件表达式作为简单 if-else 结构的简写形式,语法为:value_if_true if condition else value_if_false

示例:三元表达式的应用

# 场景:状态转换
status_code = 200

# 传统if-else写法
if status_code == 200:
    message = "成功"
else:
    message = "失败"

# 三元表达式写法(更简洁)
message = "成功" if status_code == 200 else "失败"
print(f"操作结果:{message}")  # 输出:操作结果:成功

适用场景:简单的二选一赋值操作,可使代码更紧凑。但复杂条件仍建议使用传统 if-else 结构,避免降低可读性。

4.2 循环语句

循环语句使程序能够重复执行特定代码块,直到满足终止条件。Python 提供两种基本循环结构:while 循环(基于条件)和 for 循环(基于迭代),各有其适用场景。

4.2.1 while 循环

while 循环适用于 "条件满足时持续执行" 的场景,只要条件表达式为 True,就会重复执行循环体。

语法结构:

while condition:
    # 循环体
    statement
    # 通常包含更新条件的语句

基本示例

# 场景:计数器
count = 1
while count <= 5:
    print(f"计数:{count}")
    count += 1  # 必须更新条件变量,避免无限循环

while-else 结构while 循环可与 else 搭配使用,else 代码块在循环正常结束(非 break 终止)时执行:

# 场景:尝试连接
max_attempts = 3
attempt = 0

while attempt < max_attempts:
    print(f"尝试连接 {attempt + 1}/{max_attempts}")
    # 模拟连接成功
    if attempt == 2:
        print("连接成功")
        break
    attempt += 1
else:
    # 当循环未被break终止时执行
    print(f"超过最大尝试次数({max_attempts}次)")

📌 重点提示:while 循环必须包含使条件最终为 False 的逻辑,否则会导致无限循环,耗尽系统资源。对可能无法终止的循环,应添加最大迭代次数限制。

4.2.2 for 循环

for 循环适用于遍历可迭代对象(如列表、字符串、字典等),通过迭代器依次访问每个元素。

语法结构:

for item in iterable:
    # 循环体
    statement

基本示例

# 场景:遍历列表
fruits = ["apple", "banana", "orange"]
for fruit in fruits:
    print(f"水果:{fruit}")

遍历不同类型的可迭代对象

# 场景1:遍历字符串(逐个字符)
for char in "Python":
    print(char)

# 场景2:遍历字典(键)
user = {"name": "Alice", "age": 20}
for key in user:
    print(f"{key}: {user[key]}")

# 场景3:遍历范围(使用range函数)
for i in range(1, 4):
    print(f"序号:{i}")

for-else 结构:与 while 类似,for 循环也可搭配 else,在循环正常结束时执行:

# 场景:查找元素
target = 5
numbers = [1, 3, 5, 7]

for num in numbers:
    if num == target:
        print(f"找到目标:{target}")
        break
else:
    # 当循环未找到目标且正常结束时执行
    print(f"未找到目标:{target}")

📌 性能提示:遍历列表时如需修改原列表,应遍历其副本(for item in list[:]),避免因列表长度变化导致的遍历异常。

4.2.3 循环控制语句

Python 提供三种循环控制语句,用于改变循环的执行流程:breakcontinue 和 pass

语句作用示例
break立即终止当前循环,跳出循环体if condition:break
continue跳过本次迭代剩余代码,进入下一次迭代if condition:continue
pass空操作,保持语法完整性if condition:pass

break 示例

# 场景:查找第一个偶数
numbers = [1, 3, 4, 5, 6]
for num in numbers:
    if num % 2 == 0:
        print(f"找到第一个偶数:{num}")
        break  # 找到后立即终止循环

continue 示例

# 场景:只处理偶数
numbers = [1, 2, 3, 4, 5, 6]
for num in numbers:
    if num % 2 != 0:
        continue  # 跳过奇数
    print(f"处理偶数:{num}")

pass 示例

# 场景:占位待实现功能
for i in range(3):
    if i == 1:
        pass  # 暂未实现,留待后续开发
    else:
        print(f"处理 {i}")

📌 最佳实践:避免过度使用 break 和 continue,它们可能使循环逻辑变得复杂难懂。复杂条件应考虑重构为函数返回。

4.3 迭代工具与技巧

Python 提供了丰富的内置工具简化迭代过程,使循环代码更简洁、高效。掌握这些工具能显著提升代码质量和开发效率。

4.3.1 range 函数

range 函数用于生成整数序列,是 for 循环中控制迭代次数的常用工具,语法为:range(start, stop, step)

参数含义默认值
start序列起始值(包含)0
stop序列结束值(不包含)无(必需参数)
step步长(每次递增 / 递减的值)1

基本用法示例

# 场景1:生成0-4的整数(默认start=0)
for i in range(5):
    print(i)  # 输出:0,1,2,3,4

# 场景2:生成1-5的整数
for i in range(1, 6):
    print(i)  # 输出:1,2,3,4,5

# 场景3:生成1-10的奇数(步长为2)
for i in range(1, 11, 2):
    print(i)  # 输出:1,3,5,7,9

# 场景4:生成倒序序列(步长为负)
for i in range(5, 0, -1):
    print(i)  # 输出:5,4,3,2,1

4.3.2 enumerate 函数

enumerate 函数用于同时获取序列的索引和元素,避免手动维护索引变量,语法为:enumerate(iterable, start=0)

示例:

# 场景:带索引遍历
fruits = ["apple", "banana", "orange"]

# 传统方式(需手动维护索引)
index = 0
for fruit in fruits:
    print(f"{index}: {fruit}")
    index += 1

# 使用enumerate(更简洁)
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

# 自定义起始索引
for index, fruit in enumerate(fruits, start=1):
    print(f"第{index}个水果:{fruit}")

4.3.3 zip 函数

zip 函数用于并行遍历多个序列,将对应位置的元素打包为元组,直到最短的序列结束。

示例:

# 场景:多列表并行处理
names = ["Alice", "Bob", "Charlie"]
scores = [95, 88, 92]
ages = [20, 21, 22]

# 并行遍历多个列表
for name, score, age in zip(names, scores, ages):
    print(f"{name}{age}岁):{score}分")

# 打包结果转为字典
student_dict = dict(zip(names, scores))
print(student_dict)  # 输出:{'Alice': 95, 'Bob': 88, 'Charlie': 92}

📌 扩展提示:处理不等长序列时,可使用 itertools.zip_longest 填充缺失值,确保所有元素都被处理。

4.3.4 推导式

推导式是 Python 特色语法,可在一行代码中完成基于循环的序列生成,支持列表、字典、集合和生成器。

列表推导式

# 场景1:生成平方数列表
squares = [x**2 for x in range(1, 6)]
print(squares)  # 输出:[1, 4, 9, 16, 25]

# 场景2:带条件筛选
even_numbers = [x for x in range(1, 11) if x % 2 == 0]
print(even_numbers)  # 输出:[2, 4, 6, 8, 10]

# 场景3:嵌套循环
matrix = [[1, 2], [3, 4], [5, 6]]
flattened = [num for row in matrix for num in row]
print(flattened)  # 输出:[1, 2, 3, 4, 5, 6]

字典推导式

# 场景1:生成键值对
square_dict = {x: x**2 for x in range(1, 6)}
print(square_dict)  # 输出:{1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

# 场景2:字典转换
user = {"name": "Alice", "age": 20, "city": "Beijing"}
upper_user = {k.upper(): v for k, v in user.items()}
print(upper_user)  # 输出:{'NAME': 'Alice', 'AGE': 20, 'CITY': 'Beijing'}

集合推导式

# 场景:去重并筛选
numbers = [1, 2, 2, 3, 4, 4, 5]
unique_odds = {x for x in numbers if x % 2 != 0}
print(unique_odds)  # 输出:{1, 3, 5}

📌 最佳实践:简单逻辑优先使用推导式,提升代码简洁度;但复杂逻辑(如多层循环或多条件判断)建议使用传统循环,避免可读性下降。

4.4 循环与条件的综合应用

在实际开发中,条件控制与循环通常结合使用,实现复杂的业务逻辑。以下是几个典型应用场景:

4.4.1 数据筛选与处理

# 场景:筛选并处理符合条件的数据
sales = [
    {"product": "A", "amount": 150, "region": "North"},
    {"product": "B", "amount": 80, "region": "South"},
    {"product": "A", "amount": 200, "region": "East"},
    {"product": "C", "amount": 50, "region": "North"},
    {"product": "B", "amount": 120, "region": "West"}
]

# 筛选出A产品且销售额超过100的记录,并计算总销售额
total_a = 0
high_performance = []

for sale in sales:
    if sale["product"] == "A" and sale["amount"] > 100:
        total_a += sale["amount"]
        high_performance.append(sale)

print(f"A产品高销售额记录:{high_performance}")
print(f"A产品高销售额总和:{total_a}")

4.4.2 菜单与用户交互

# 场景:命令行菜单交互
def show_menu():
    print("\n===== 操作菜单 =====")
    print("1. 添加数据")
    print("2. 查看数据")
    print("3. 保存数据")
    print("0. 退出程序")
    return input("请选择操作(0-3):")

data = []
while True:
    choice = show_menu()
    
    if choice == "1":
        item = input("请输入要添加的数据:")
        data.append(item)
        print(f"已添加:{item}")
        
    elif choice == "2":
        print("\n当前数据:")
        for i, item in enumerate(data, 1):
            print(f"{i}. {item}")
            
    elif choice == "3":
        # 模拟保存操作
        print(f"已保存 {len(data)} 条数据")
        
    elif choice == "0":
        print("程序退出,再见!")
        break
        
    else:
        print("无效选择,请重试")

4.4.3 批量文件处理

import os

# 场景:批量处理文件夹中的文件
def process_files(folder_path):
    # 获取文件夹中所有txt文件
    txt_files = [f for f in os.listdir(folder_path) 
                if f.endswith(".txt") and os.path.isfile(os.path.join(folder_path, f))]
    
    if not txt_files:
        print("未找到txt文件")
        return
    
    # 遍历处理每个文件
    for file in txt_files:
        file_path = os.path.join(folder_path, file)
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                content = f.read()
                word_count = len(content.split())
            
            print(f"{file}: {word_count} 个单词")
            
        except Exception as e:
            print(f"处理 {file} 失败:{str(e)}")

# 使用示例
process_files("documents")

4.5 工程实践与优化技巧

合理使用条件控制与循环结构,对代码的可读性、性能和可维护性至关重要。以下是一些实践建议:

4.5.1 循环优化策略

  1. 减少循环内的计算:将循环外可计算的值移到循环外,避免重复计算

    # 不推荐:每次迭代都计算len(data)
    data = [1, 2, 3, 4, 5]
    for i in range(len(data)):
        print(f"{i}/{len(data)}: {data[i]}")
    
    # 推荐:提前计算长度
    data = [1, 2, 3, 4, 5]
    data_len = len(data)
    for i in range(data_len):
        print(f"{i}/{data_len}: {data[i]}")
    
  2. 使用内置函数替代循环:Python 内置函数(如 mapfiltersum 等)通常由 C 实现,效率更高

    # 不推荐:手动循环计算总和
    numbers = [1, 2, 3, 4, 5]
    total = 0
    for num in numbers:
        total += num
    
    # 推荐:使用内置sum函数
    total = sum(numbers)
    
  3. 优先使用局部变量:在循环中访问局部变量比全局变量更快

    # 优化前:访问全局变量
    global_list = [1, 2, 3, 4, 5]
    
    def process():
        total = 0
        for item in global_list:  # 访问全局变量
            total += item
        return total
    
    # 优化后:使用局部变量
    def process():
        local_list = [1, 2, 3, 4, 5]  # 局部变量
        total = 0
        for item in local_list:  # 访问局部变量
            total += item
        return total
    

4.5.2 条件判断优化

  1. 将高频条件放在前面:在 if-elif-else 结构中,将更可能为真的条件放在前面

    # 假设多数用户年龄在18-60岁之间
    age = 30
    
    # 优化前:低频条件在前
    if age < 18:
        category = "青少年"
    elif age > 60:
        category = "老年"
    else:
        category = "成年"
    
    # 优化后:高频条件在前
    if 18 <= age <= 60:
        category = "成年"
    elif age < 18:
        category = "青少年"
    else:
        category = "老年"
    
  2. 使用字典替代复杂条件:过多的 elif 分支可改用字典映射,提升可读性

    # 不推荐:过多的elif分支
    def handle_command(cmd):
        if cmd == "add":
            return "执行添加操作"
        elif cmd == "delete":
            return "执行删除操作"
        elif cmd == "update":
            return "执行更新操作"
        elif cmd == "query":
            return "执行查询操作"
        else:
            return "未知命令"
    
    # 推荐:使用字典映射
    def handle_command(cmd):
        commands = {
            "add": "执行添加操作",
            "delete": "执行删除操作",
            "update": "执行更新操作",
            "query": "执行查询操作"
        }
        return commands.get(cmd, "未知命令")
    
  3. 提前返回减少嵌套:使用提前返回代替嵌套条件,使代码更扁平

    # 不推荐:深层嵌套
    def process_data(data):
        if data is not None:
            if len(data) > 0:
                if data[0] == "valid":
                    return "处理数据"
                else:
                    return "数据无效"
            else:
                return "数据为空"
        else:
            return "无数据"
    
    # 推荐:提前返回
    def process_data(data):
        if data is None:
            return "无数据"
        if len(data) == 0:
            return "数据为空"
        if data[0] != "valid":
            return "数据无效"
        return "处理数据"
    

4.5.3 避免常见陷阱

  1. 无限循环:始终确保循环条件最终会变为 False

    # 危险:可能无限循环
    count = 0
    while count < 5:
        print(count)
        # 忘记更新count变量,导致无限循环
    
    # 安全:确保更新条件
    count = 0
    while count < 5:
        print(count)
        count += 1  # 正确更新条件变量
    
  2. 修改正在遍历的序列:遍历列表时修改列表可能导致意外结果

    # 危险:遍历中修改列表
    numbers = [1, 2, 3, 4, 5]
    for num in numbers:
        if num % 2 == 0:
            numbers.remove(num)  # 会导致遍历异常
    
    # 安全:遍历副本
    numbers = [1, 2, 3, 4, 5]
    for num in numbers[:]:  # 遍历副本
        if num % 2 == 0:
            numbers.remove(num)  # 安全修改原列表
    
  3. 混淆 == 与 is== 判断值相等,is 判断对象相同

    a = [1, 2, 3]
    b = [1, 2, 3]
    
    print(a == b)  # True(值相等)
    print(a is b)  # False(不是同一对象)