Python 语法之控制结构详解

全面解析Python流程控制语句及其使用案例


目录

  1. 条件语句 (if/elif/else)
  2. 循环语句
  3. 循环控制语句
  4. 异常处理 (try/except)
  5. 上下文管理器 (with语句)
  6. 推导式与生成器表达式
  7. 模式匹配 (match/case)
  8. 实战案例

1. 条件语句 (if/elif/else)

1.1 基本语法

复制代码
age = 18

if age < 13:
    category = "儿童"
elif age < 20:
    category = "青少年"  # 输出
else:
    category = "成年人"

print(f"年龄分类: {category}")

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

复制代码
# 传统写法
if score >= 60:
    result = "及格"
else:
    result = "不及格"

# 三元表达式 (更简洁)
result = "及格" if score >= 60 else "不及格"

# 嵌套三元表达式
grade = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"

1.3 真值判断

复制代码
# Python中以下值被视为False:
# False, None, 0, 0.0, 0j, "", [], {}, (), set(), frozenset(), range(0)

# 检查列表是否为空
items = []
if items:  # 不推荐: if len(items) > 0
    print("列表不为空")
else:
    print("列表为空")  # 输出

# 检查变量是否为None
value = None
if value is None:  # 推荐用is判断None
    print("值为None")

# 同时检查多个条件
x = 10
if 5 < x < 15:  # Python支持链式比较
    print("x在5到15之间")  # 输出

1.4 逻辑运算符

复制代码
# and, or, not
age = 25
income = 5000

if age > 18 and income > 3000:
    print("符合贷款条件")

# 短路求值
result = func_a() or func_b()  # 如果func_a()返回真值,不执行func_b()
result = func_a() and func_b() # 如果func_a()返回假值,不执行func_b()

# 使用or提供默认值
username = user_input or "匿名用户"

2. 循环语句

2.1 for循环

基本遍历

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

# 遍历字符串
for char in "Python":
    print(char, end="-")  # P-y-t-h-o-n-

# 使用range()
for i in range(5):        # 0, 1, 2, 3, 4
    print(i)

for i in range(1, 10, 2): # 1, 3, 5, 7, 9
    print(i)

使用enumerate获取索引

复制代码
names = ["Alice", "Bob", "Charlie"]

# 不推荐
for i in range(len(names)):
    print(f"{i}: {names[i]}")

# 推荐
for index, name in enumerate(names):
    print(f"{index}: {name}")

# 指定起始索引
for index, name in enumerate(names, start=1):
    print(f"{index}. {name}")  # 1. Alice, 2. Bob, 3. Charlie

使用zip并行迭代

复制代码
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["北京", "上海", "广州"]

# 同时遍历多个序列
for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 来自{city}")

# zip以最短序列为准
short = [1, 2]
long = ["a", "b", "c", "d"]
for s, l in zip(short, long):
    print(s, l)  # 只输出两组

# Python 3.10+ zip_strict模式
# for x, y in zip(list1, list2, strict=True):  # 长度不等会报错

遍历字典

复制代码
user = {"name": "Alice", "age": 25, "city": "北京"}

# 遍历键
for key in user:
    print(key)

# 遍历值
for value in user.values():
    print(value)

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

# 遍历时修改字典 (需要list转换)
for key in list(user.keys()):
    if key == "age":
        del user[key]

反向遍历与排序遍历

复制代码
# 反向遍历
for i in reversed(range(5)):
    print(i)  # 4, 3, 2, 1, 0

# 排序后遍历
for fruit in sorted(fruits, reverse=True):
    print(fruit)

# 按值排序遍历字典
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}
for name, score in sorted(scores.items(), key=lambda x: x[1], reverse=True):
    print(f"{name}: {score}")

2.2 while循环

基本语法

复制代码
# 基本while循环
count = 0
while count < 5:
    print(count)
    count += 1

# 无限循环 (需要break退出)
while True:
    user_input = input("输入'quit'退出: ")
    if user_input.lower() == 'quit':
        break
    print(f"你输入了: {user_input}")

while与else结合

复制代码
# 查找质数
n = 17
divisor = 2

while divisor * divisor <= n:
    if n % divisor == 0:
        print(f"{n}不是质数,能被{divisor}整除")
        break
    divisor += 1
else:
    # 循环正常结束(没有被break)时执行
    print(f"{n}是质数")

3. 循环控制语句

3.1 break

复制代码
# 查找第一个符合条件的元素
numbers = [1, 3, 5, 7, 8, 9, 10]

for num in numbers:
    if num % 2 == 0:
        print(f"找到第一个偶数: {num}")  # 8
        break

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

3.2 continue

复制代码
# 跳过某些元素
for num in range(10):
    if num % 2 == 0:
        continue  # 跳过偶数
    print(num)  # 输出1, 3, 5, 7, 9

# 处理数据时跳过无效项
data = [1, 2, None, 4, None, 6]
for item in data:
    if item is None:
        continue
    print(f"处理数据: {item}")

3.3 else子句

复制代码
# for循环的else
target = 7
for i in range(5):
    if i == target:
        print("找到目标")
        break
else:
    print("未找到目标")  # 输出,因为range(5)是0-4

# 实际应用:验证列表中所有元素
def all_positive(numbers):
    for num in numbers:
        if num <= 0:
            print(f"发现非正数: {num}")
            break
    else:
        print("所有数字都是正数")
        return True
    return False

all_positive([1, 2, 3, 4])   # 所有数字都是正数
all_positive([1, -2, 3, 4])  # 发现非正数: -2

4. 异常处理 (try/except)

4.1 基本结构

复制代码
try:
    result = 10 / 0
except ZeroDivisionError:
    print("不能除以零!")
except TypeError:
    print("类型错误!")
except Exception as e:
    print(f"其他错误: {e}")
else:
    print(f"计算结果: {result}")  # 没有异常时执行
finally:
    print("无论如何都会执行")  # 清理资源

4.2 捕获多个异常

复制代码
def safe_divide(a, b):
    try:
        result = a / b
    except (ZeroDivisionError, TypeError) as e:
        print(f"错误: {e}")
        return None
    return result

# 忽略特定异常
try:
    risky_operation()
except SpecificError:
    pass  # 静默处理

4.3 自定义异常与raise

复制代码
class ValidationError(Exception):
    """自定义验证错误"""
    pass

def validate_age(age):
    if age < 0:
        raise ValidationError("年龄不能为负数")
    if age > 150:
        raise ValidationError("年龄不能超过150")
    return True

# 使用from保留异常链
try:
    int("not a number")
except ValueError as e:
    raise RuntimeError("转换失败") from e

4.4 assert断言

复制代码
def divide(a, b):
    assert b != 0, "除数不能为零"  # 开发调试时使用
    return a / b

# 生产环境建议用异常处理代替assert

5. 上下文管理器 (with语句)

5.1 文件操作

复制代码
# 传统写法
f = open('file.txt', 'r')
try:
    content = f.read()
finally:
    f.close()

# 使用with语句 (推荐)
with open('file.txt', 'r') as f:
    content = f.read()
# 自动关闭文件,即使发生异常

# 同时管理多个资源
with open('input.txt', 'r') as infile, open('output.txt', 'w') as outfile:
    outfile.write(infile.read())

5.2 自定义上下文管理器

复制代码
from contextlib import contextmanager

class DatabaseConnection:
    def __enter__(self):
        print("连接数据库...")
        self.conn = "数据库连接对象"
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("关闭数据库连接...")
        if exc_type:
            print(f"发生异常: {exc_val}")
        return False  # 不抑制异常

# 使用
with DatabaseConnection() as conn:
    print(f"使用{conn}进行操作")

# 使用装饰器简化
@contextmanager
def managed_resource(name):
    print(f"获取资源: {name}")
    resource = f"资源-{name}"
    try:
        yield resource
    finally:
        print(f"释放资源: {name}")

with managed_resource("数据库") as res:
    print(f"使用{res}")

6. 推导式与生成器表达式

6.1 列表推导式

复制代码
# 基本形式
squares = [x**2 for x in range(10)]

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

# 多重循环
combinations = [(x, y) for x in [1, 2, 3] for y in [3, 1, 4] if x != y]

# 嵌套列表推导式
matrix = [[i*j for j in range(1, 4)] for i in range(1, 4)]
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

6.2 字典和集合推导式

复制代码
# 字典推导式
word_lengths = {word: len(word) for word in ["apple", "banana", "cherry"]}
# {'apple': 5, 'banana': 6, 'cherry': 6}

# 集合推导式
unique_lengths = {len(word) for word in ["apple", "banana", "cherry", "date"]}
# {4, 5, 6}

6.3 生成器表达式

复制代码
# 使用圆括号创建生成器 (惰性求值)
sum_of_squares = sum(x**2 for x in range(1000000))  # 内存友好

# 与列表推导式对比
list_comp = [x**2 for x in range(1000000)]  # 占用大量内存
gen_exp = (x**2 for x in range(1000000))     # 几乎不占内存

# 生成器只能遍历一次
gen = (x for x in range(5))
print(list(gen))  # [0, 1, 2, 3, 4]
print(list(gen))  # [] (已耗尽)

7. 模式匹配 (match/case) Python 3.10+

7.1 基本匹配

复制代码
def handle_command(command):
    match command:
        case "quit":
            return "退出程序"
        case "start":
            return "开始运行"
        case "stop":
            return "停止运行"
        case _:  # 通配符,相当于default
            return f"未知命令: {command}"

print(handle_command("start"))  # 开始运行
print(handle_command("pause"))  # 未知命令: pause

7.2 结构模式匹配

复制代码
def describe_point(point):
    match point:
        case (0, 0):
            return "原点"
        case (x, 0):
            return f"x轴上,x={x}"
        case (0, y):
            return f"y轴上,y={y}"
        case (x, y):
            return f"点({x}, {y})"
        case _:
            return "不是点"

print(describe_point((0, 0)))     # 原点
print(describe_point((5, 0)))     # x轴上,x=5
print(describe_point((3, 4)))     # 点(3, 4)

7.3 匹配数据结构

复制代码
def analyze_data(data):
    match data:
        case {"type": "user", "name": str(name), "age": int(age)}:
            return f"用户: {name}, {age}岁"
        case {"type": "product", "name": name, "price": price}:
            return f"产品: {name}, 价格: {price}"
        case [x, y, *rest]:
            return f"列表,前两个元素: {x}, {y}, 其余: {rest}"
        case _:
            return "未知数据类型"

print(analyze_data({"type": "user", "name": "Alice", "age": 25}))
# 用户: Alice, 25岁

print(analyze_data([1, 2, 3, 4, 5]))
# 列表,前两个元素: 1, 2, 其余: [3, 4, 5]

7.4 带守卫子句的匹配

复制代码
def classify_age(age):
    match age:
        case n if n < 0:
            return "无效年龄"
        case n if n < 13:
            return "儿童"
        case n if n < 20:
            return "青少年"
        case n if n < 60:
            return "成年人"
        case _:
            return "老年人"

print(classify_age(25))   # 成年人
print(classify_age(-5))   # 无效年龄

8. 实战案例

8.1 菜单驱动程序

复制代码
def show_menu():
    print("\n" + "="*30)
    print("1. 查看所有任务")
    print("2. 添加任务")
    print("3. 删除任务")
    print("4. 标记完成")
    print("5. 退出")
    print("="*30)

def main():
    tasks = []

    while True:
        show_menu()
        choice = input("请选择操作 (1-5): ").strip()

        match choice:
            case "1":
                if not tasks:
                    print("暂无任务")
                else:
                    for i, task in enumerate(tasks, 1):
                        status = "✓" if task["done"] else "✗"
                        print(f"{i}. [{status}] {task['name']}")

            case "2":
                name = input("输入任务名称: ").strip()
                if name:
                    tasks.append({"name": name, "done": False})
                    print("任务添加成功!")

            case "3":
                try:
                    idx = int(input("输入要删除的任务编号: ")) - 1
                    if 0 <= idx < len(tasks):
                        removed = tasks.pop(idx)
                        print(f"已删除: {removed['name']}")
                    else:
                        print("无效编号")
                except ValueError:
                    print("请输入数字")

            case "4":
                try:
                    idx = int(input("输入要标记的任务编号: ")) - 1
                    if 0 <= idx < len(tasks):
                        tasks[idx]["done"] = True
                        print("标记完成!")
                    else:
                        print("无效编号")
                except ValueError:
                    print("请输入数字")

            case "5":
                confirm = input("确定退出? (y/n): ").lower()
                if confirm == 'y':
                    print("再见!")
                    break

            case _:
                print("无效选择,请重试")

if __name__ == "__main__":
    main()

8.2 文件批处理

复制代码
import os
from pathlib import Path

def batch_rename(directory, old_ext, new_ext):
    """批量修改文件扩展名"""
    path = Path(directory)

    if not path.exists():
        print(f"目录不存在: {directory}")
        return

    files = list(path.glob(f"*.{old_ext}"))

    if not files:
        print(f"没有找到 .{old_ext} 文件")
        return

    print(f"找到 {len(files)} 个文件待处理")
    confirm = input("确认重命名? (y/n): ").lower()

    if confirm != 'y':
        print("操作已取消")
        return

    success_count = 0
    for file_path in files:
        try:
            new_name = file_path.stem + f".{new_ext}"
            new_path = file_path.with_name(new_name)
            file_path.rename(new_path)
            print(f"重命名: {file_path.name} -> {new_name}")
            success_count += 1
        except Exception as e:
            print(f"错误处理 {file_path.name}: {e}")

    print(f"\n完成!成功重命名 {success_count}/{len(files)} 个文件")

# 使用示例
# batch_rename("./documents", "txt", "md")

8.3 数据验证器

复制代码
from typing import Any, Dict, List

class DataValidator:
    @staticmethod
    def validate_user(data: Dict[str, Any]) -> Dict[str, str]:
        errors = {}

        # 验证必填字段
        required = ["name", "email", "age"]
        for field in required:
            if field not in data:
                errors[field] = f"缺少必填字段: {field}"

        if errors:
            return errors

        # 验证name
        name = data["name"]
        if not isinstance(name, str):
            errors["name"] = "name必须是字符串"
        elif len(name) < 2:
            errors["name"] = "name长度至少为2"

        # 验证email
        email = data["email"]
        if not isinstance(email, str):
            errors["email"] = "email必须是字符串"
        elif "@" not in email:
            errors["email"] = "email格式不正确"

        # 验证age
        age = data["age"]
        if not isinstance(age, int):
            errors["age"] = "age必须是整数"
        elif not (0 <= age <= 150):
            errors["age"] = "age必须在0-150之间"

        return errors

# 使用示例
test_data = [
    {"name": "A", "email": "test@example.com", "age": 25},
    {"name": "Bob", "email": "invalid-email", "age": 200},
    {"email": "test@example.com", "age": 25},  # 缺少name
]

for data in test_data:
    errors = DataValidator.validate_user(data)
    if errors:
        print(f"验证失败: {errors}")
    else:
        print(f"验证通过: {data['name']}")

8.4 递归与迭代对比

复制代码
# 斐波那契数列 - 递归版 (低效)
def fib_recursive(n):
    if n <= 1:
        return n
    return fib_recursive(n-1) + fib_recursive(n-2)

# 斐波那契数列 - 迭代版 (高效)
def fib_iterative(n):
    if n <= 1:
        return n
    a, b = 0, 1
    for _ in range(2, n + 1):
        a, b = b, a + b
    return b

# 斐波那契数列 - 生成器版 (内存友好)
def fib_generator(max_n):
    a, b = 0, 1
    for _ in range(max_n):
        yield a
        a, b = b, a + b

# 性能对比
import time

n = 30

start = time.time()
result = fib_recursive(n)
print(f"递归版结果: {result}, 耗时: {time.time()-start:.4f}秒")

start = time.time()
result = fib_iterative(n)
print(f"迭代版结果: {result}, 耗时: {time.time()-start:.6f}秒")

print(f"生成器版前10项: {list(fib_generator(10))}")

总结

Python的控制结构以其简洁和可读性著称:

控制结构 关键特性 最佳实践
if/elif/else 链式比较、真值判断 避免嵌套过深,使用早期返回
for循环 迭代协议、enumerate、zip 优先用for而非while遍历序列
while循环 条件控制、无限循环 确保有退出条件,避免死循环
break/continue 循环控制 适度使用,避免逻辑过于复杂
try/except 异常处理、上下文管理 捕获具体异常,不滥用 bare except
with语句 资源管理 文件、锁等资源使用with语句
推导式 简洁、高效 简单逻辑用推导式,复杂逻辑用普通循环
match/case 模式匹配(Python 3.10+) 替代复杂的if/elif链
相关推荐
咚为2 小时前
深入理解 Rust 的静态分发与动态分发:从 `impl Trait` 到 `dyn Trait`
开发语言·后端·rust
xcbrand2 小时前
工业制造品牌全案公司找哪家
大数据·人工智能·python·制造
深蓝海拓2 小时前
基于QtPy (PySide6) 的PLC-HMI工程项目(七)上位机通信部分的初步建设:socket客户端
网络·笔记·python·学习·plc
神秘剑客_CN2 小时前
python安装requests及pandas
开发语言·python·pandas
人工智能AI技术2 小时前
Python 循环基础:for、while、break、continue
python
代码改善世界2 小时前
【C++初阶】stack和queue用法详解:常用接口、模拟实现与面试题(附完整代码)
开发语言·c++
hef2882 小时前
如何查找SQL字符串中字符数_掌握CHAR_LENGTH应用
jvm·数据库·python
AI效率工坊2 小时前
【Python实战】自动化生成PPT演示文稿:python-pptx+AI内容生成+图表嵌入
人工智能·python·自动化
少司府2 小时前
C++基础入门:类和对象(下)
开发语言·c++·类型转换·类和对象·友元