学习目标

通过本章学习,你将掌握: - 条件语句的使用(if/elif/else) - 循环语句的应用(for/while) - 循环控制语句(break/continue/pass) - 异常处理机制(try/except/finally) - 上下文管理器(with语句) - 推导式的使用

4.1 条件语句

if语句基础

# 基本if语句
age = 18
if age >= 18:
    print("你已经成年了")

# if-else语句
score = 85
if score >= 60:
    print("考试通过")
else:
    print("考试不通过")

# if-elif-else语句
score = 92
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(f"你的成绩等级是: {grade}")

# 嵌套if语句
weather = "sunny"
temperature = 25

if weather == "sunny":
    if temperature > 20:
        print("天气很好,适合外出")
    else:
        print("天气晴朗但有点冷")
else:
    print("天气不太好")

条件表达式(三元运算符)

# 条件表达式的语法:value_if_true if condition else value_if_false
age = 20
status = "成年人" if age >= 18 else "未成年人"
print(f"你是{status}")

# 比较传统写法
if age >= 18:
    status = "成年人"
else:
    status = "未成年人"

# 更复杂的条件表达式
score = 85
result = "优秀" if score >= 90 else "良好" if score >= 80 else "及格" if score >= 60 else "不及格"
print(f"成绩评价: {result}")

# 在函数调用中使用
def get_discount(is_member, purchase_amount):
    return 0.1 if is_member else 0.05 if purchase_amount > 100 else 0

discount = get_discount(True, 150)
print(f"折扣率: {discount:.1%}")

# 在列表操作中使用
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
even_or_odd = ["偶数" if x % 2 == 0 else "奇数" for x in numbers]
print(even_or_odd)

复杂条件判断

# 多条件组合
username = "admin"
password = "123456"
is_active = True

if username == "admin" and password == "123456" and is_active:
    print("登录成功")
else:
    print("登录失败")

# 使用in操作符
user_role = "manager"
allowed_roles = ["admin", "manager", "supervisor"]

if user_role in allowed_roles:
    print("有权限访问")
else:
    print("权限不足")

# 检查多个条件
age = 25
income = 50000
credit_score = 750

# 贷款审批条件
if (age >= 18 and age <= 65) and income >= 30000 and credit_score >= 700:
    print("贷款申请通过")
else:
    reasons = []
    if not (18 <= age <= 65):
        reasons.append("年龄不符合要求")
    if income < 30000:
        reasons.append("收入不足")
    if credit_score < 700:
        reasons.append("信用评分过低")
    
    print(f"贷款申请被拒绝,原因: {', '.join(reasons)}")

# 使用any()和all()函数
scores = [85, 92, 78, 96, 88]

# 检查是否所有成绩都及格
if all(score >= 60 for score in scores):
    print("所有科目都及格")
else:
    print("有科目不及格")

# 检查是否有优秀成绩
if any(score >= 90 for score in scores):
    print("有优秀成绩")
else:
    print("没有优秀成绩")

4.2 循环语句

for循环

# 遍历列表
fruits = ["apple", "banana", "orange", "grape"]
for fruit in fruits:
    print(f"我喜欢{fruit}")

# 遍历字符串
word = "Python"
for char in word:
    print(char, end=" ")
print()  # 换行

# 使用range()函数
print("使用range(5):")
for i in range(5):
    print(i, end=" ")
print()

print("使用range(1, 6):")
for i in range(1, 6):
    print(i, end=" ")
print()

print("使用range(0, 10, 2):")
for i in range(0, 10, 2):
    print(i, end=" ")
print()

# 遍历字典
student = {"name": "Alice", "age": 20, "major": "Computer Science"}

# 遍历键
print("遍历键:")
for key in student:
    print(key)

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

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

# 使用enumerate()获取索引
fruits = ["apple", "banana", "orange"]
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

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

# 使用zip()同时遍历多个序列
names = ["Alice", "Bob", "Charlie"]
ages = [25, 30, 35]
cities = ["北京", "上海", "广州"]

for name, age, city in zip(names, ages, cities):
    print(f"{name}, {age}岁, 来自{city}")

# 嵌套循环
print("九九乘法表:")
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f"{j}×{i}={i*j}", end="\t")
    print()  # 换行

while循环

# 基本while循环
count = 0
while count < 5:
    print(f"计数: {count}")
    count += 1

# 用户输入验证
while True:
    password = input("请输入密码: ")
    if password == "123456":
        print("密码正确")
        break
    else:
        print("密码错误,请重试")

# 计算数字的各位数字之和
number = 12345
digit_sum = 0
temp = number

while temp > 0:
    digit = temp % 10
    digit_sum += digit
    temp //= 10

print(f"{number}的各位数字之和是: {digit_sum}")

# 猜数字游戏
import random

target = random.randint(1, 100)
attempts = 0
max_attempts = 7

print("猜数字游戏!我想了一个1-100之间的数字。")
print(f"你有{max_attempts}次机会。")

while attempts < max_attempts:
    try:
        guess = int(input(f"第{attempts + 1}次猜测: "))
        attempts += 1
        
        if guess == target:
            print(f"恭喜!你猜对了!数字是{target}")
            print(f"你用了{attempts}次猜测")
            break
        elif guess < target:
            print("太小了!")
        else:
            print("太大了!")
        
        remaining = max_attempts - attempts
        if remaining > 0:
            print(f"还有{remaining}次机会")
    
    except ValueError:
        print("请输入有效的数字")
        attempts -= 1  # 无效输入不计入尝试次数
else:
    print(f"游戏结束!正确答案是{target}")

循环控制语句

# break语句:跳出循环
print("使用break:")
for i in range(10):
    if i == 5:
        break
    print(i, end=" ")
print("\n循环结束")

# continue语句:跳过当前迭代
print("使用continue(跳过偶数):")
for i in range(10):
    if i % 2 == 0:
        continue
    print(i, end=" ")
print("\n循环结束")

# pass语句:占位符
print("使用pass:")
for i in range(5):
    if i == 2:
        pass  # 什么都不做,占位符
    print(i, end=" ")
print("\n循环结束")

# 在嵌套循环中使用break和continue
print("嵌套循环中的break:")
for i in range(3):
    print(f"外层循环 i={i}")
    for j in range(5):
        if j == 3:
            break  # 只跳出内层循环
        print(f"  内层循环 j={j}")

# 使用标志变量跳出嵌套循环
print("使用标志变量跳出嵌套循环:")
found = False
for i in range(3):
    if found:
        break
    for j in range(5):
        if i == 1 and j == 2:
            print(f"找到目标: i={i}, j={j}")
            found = True
            break
        print(f"i={i}, j={j}")

# else子句:循环正常结束时执行
print("for循环的else子句:")
for i in range(5):
    print(i, end=" ")
else:
    print("\n循环正常结束")

print("被break中断的循环:")
for i in range(5):
    if i == 3:
        break
    print(i, end=" ")
else:
    print("\n循环正常结束")  # 这行不会执行
print("循环被中断")

4.3 异常处理

基本异常处理

# 基本try-except结构
try:
    number = int(input("请输入一个数字: "))
    result = 10 / number
    print(f"10 / {number} = {result}")
except ValueError:
    print("输入的不是有效数字")
except ZeroDivisionError:
    print("不能除以零")

# 捕获多种异常
try:
    data = [1, 2, 3]
    index = int(input("请输入索引: "))
    print(f"data[{index}] = {data[index]}")
except (ValueError, IndexError) as e:
    print(f"发生错误: {e}")

# 捕获所有异常
try:
    # 一些可能出错的代码
    result = eval(input("请输入一个表达式: "))
    print(f"结果: {result}")
except Exception as e:
    print(f"发生未知错误: {type(e).__name__}: {e}")

# try-except-else-finally结构
def safe_divide(a, b):
    try:
        result = a / b
    except ZeroDivisionError:
        print("错误:除数不能为零")
        return None
    except TypeError:
        print("错误:参数类型不正确")
        return None
    else:
        print("计算成功")
        return result
    finally:
        print("清理工作完成")

print(safe_divide(10, 2))
print(safe_divide(10, 0))
print(safe_divide("10", 2))

自定义异常

# 定义自定义异常类
class CustomError(Exception):
    """自定义异常基类"""
    pass

class ValidationError(CustomError):
    """验证错误"""
    def __init__(self, message, field=None):
        super().__init__(message)
        self.field = field

class BusinessLogicError(CustomError):
    """业务逻辑错误"""
    pass

# 使用自定义异常
def validate_age(age):
    if not isinstance(age, int):
        raise ValidationError("年龄必须是整数", "age")
    if age < 0:
        raise ValidationError("年龄不能为负数", "age")
    if age > 150:
        raise ValidationError("年龄不能超过150岁", "age")
    return True

def process_user_registration(name, age, email):
    try:
        # 验证输入
        if not name.strip():
            raise ValidationError("姓名不能为空", "name")
        
        validate_age(age)
        
        if "@" not in email:
            raise ValidationError("邮箱格式不正确", "email")
        
        # 模拟业务逻辑
        if age < 18:
            raise BusinessLogicError("用户必须年满18岁才能注册")
        
        print(f"用户 {name} 注册成功")
        return True
        
    except ValidationError as e:
        print(f"验证错误 ({e.field}): {e}")
        return False
    except BusinessLogicError as e:
        print(f"业务逻辑错误: {e}")
        return False
    except Exception as e:
        print(f"系统错误: {e}")
        return False

# 测试自定义异常
process_user_registration("Alice", 25, "alice@example.com")
process_user_registration("", 25, "alice@example.com")
process_user_registration("Bob", -5, "bob@example.com")
process_user_registration("Charlie", 16, "charlie@example.com")

异常处理最佳实践

import logging
import traceback
from typing import Optional, Union

# 配置日志
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class FileProcessor:
    """文件处理器示例"""
    
    def __init__(self, filename: str):
        self.filename = filename
    
    def read_file(self) -> Optional[str]:
        """安全地读取文件"""
        try:
            with open(self.filename, 'r', encoding='utf-8') as file:
                content = file.read()
                logger.info(f"成功读取文件: {self.filename}")
                return content
        except FileNotFoundError:
            logger.error(f"文件不存在: {self.filename}")
            return None
        except PermissionError:
            logger.error(f"没有权限读取文件: {self.filename}")
            return None
        except UnicodeDecodeError:
            logger.error(f"文件编码错误: {self.filename}")
            return None
        except Exception as e:
            logger.error(f"读取文件时发生未知错误: {e}")
            logger.debug(traceback.format_exc())  # 记录完整的错误堆栈
            return None
    
    def write_file(self, content: str) -> bool:
        """安全地写入文件"""
        try:
            with open(self.filename, 'w', encoding='utf-8') as file:
                file.write(content)
                logger.info(f"成功写入文件: {self.filename}")
                return True
        except PermissionError:
            logger.error(f"没有权限写入文件: {self.filename}")
            return False
        except OSError as e:
            logger.error(f"写入文件时发生系统错误: {e}")
            return False
        except Exception as e:
            logger.error(f"写入文件时发生未知错误: {e}")
            return False

# 重试机制
def retry_operation(func, max_attempts=3, delay=1):
    """重试装饰器"""
    import time
    
    def wrapper(*args, **kwargs):
        for attempt in range(max_attempts):
            try:
                return func(*args, **kwargs)
            except Exception as e:
                if attempt == max_attempts - 1:
                    logger.error(f"操作失败,已重试{max_attempts}次: {e}")
                    raise
                else:
                    logger.warning(f"操作失败,第{attempt + 1}次重试: {e}")
                    time.sleep(delay)
    
    return wrapper

# 使用重试机制
@retry_operation
def unreliable_network_call():
    import random
    if random.random() < 0.7:  # 70%的概率失败
        raise ConnectionError("网络连接失败")
    return "网络请求成功"

# 测试异常处理
if __name__ == "__main__":
    # 测试文件处理
    processor = FileProcessor("test.txt")
    
    # 写入测试内容
    if processor.write_file("这是测试内容\n第二行内容"):
        # 读取内容
        content = processor.read_file()
        if content:
            print(f"文件内容:\n{content}")
    
    # 测试重试机制
    try:
        result = unreliable_network_call()
        print(result)
    except Exception as e:
        print(f"最终失败: {e}")

4.4 上下文管理器

with语句基础

# 传统文件操作(不推荐)
file = open("example.txt", "w")
try:
    file.write("Hello, World!")
finally:
    file.close()

# 使用with语句(推荐)
with open("example.txt", "w", encoding="utf-8") as file:
    file.write("Hello, World!")
# 文件会自动关闭

# 同时打开多个文件
with open("input.txt", "r", encoding="utf-8") as infile, \
     open("output.txt", "w", encoding="utf-8") as outfile:
    content = infile.read()
    outfile.write(content.upper())

# 自定义上下文管理器
class Timer:
    """计时器上下文管理器"""
    
    def __init__(self, name="操作"):
        self.name = name
    
    def __enter__(self):
        import time
        self.start_time = time.time()
        print(f"{self.name}开始...")
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        import time
        end_time = time.time()
        duration = end_time - self.start_time
        print(f"{self.name}完成,耗时: {duration:.2f}秒")
        
        if exc_type is not None:
            print(f"发生异常: {exc_type.__name__}: {exc_val}")
        
        return False  # 不抑制异常

# 使用自定义上下文管理器
with Timer("数据处理"):
    import time
    time.sleep(1)  # 模拟耗时操作
    data = [i ** 2 for i in range(1000000)]
    print(f"处理了{len(data)}个数据")

# 使用contextlib模块
from contextlib import contextmanager

@contextmanager
def database_connection():
    """数据库连接上下文管理器"""
    print("连接数据库...")
    connection = "数据库连接对象"  # 模拟连接
    try:
        yield connection
    except Exception as e:
        print(f"数据库操作出错: {e}")
        print("回滚事务...")
        raise
    else:
        print("提交事务...")
    finally:
        print("关闭数据库连接")

# 使用数据库连接
with database_connection() as conn:
    print(f"使用连接: {conn}")
    print("执行数据库操作...")

# 异常抑制
from contextlib import suppress

# 忽略特定异常
with suppress(FileNotFoundError):
    with open("nonexistent.txt", "r") as f:
        content = f.read()

print("程序继续执行...")

# 临时改变工作目录
import os
from contextlib import contextmanager

@contextmanager
def change_directory(path):
    """临时改变工作目录"""
    old_path = os.getcwd()
    try:
        os.chdir(path)
        yield
    finally:
        os.chdir(old_path)

# 使用目录切换
print(f"当前目录: {os.getcwd()}")
with change_directory("/tmp" if os.name != 'nt' else "C:\\temp"):
    print(f"临时目录: {os.getcwd()}")
print(f"恢复目录: {os.getcwd()}")

4.5 推导式

列表推导式

# 基本列表推导式
numbers = [1, 2, 3, 4, 5]
squares = [x ** 2 for x in numbers]
print(f"平方数: {squares}")

# 带条件的列表推导式
even_squares = [x ** 2 for x in numbers if x % 2 == 0]
print(f"偶数的平方: {even_squares}")

# 复杂表达式
words = ["hello", "world", "python", "programming"]
capitalized = [word.capitalize() for word in words if len(word) > 5]
print(f"长度大于5的单词(首字母大写): {capitalized}")

# 嵌套循环
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flattened = [item for row in matrix for item in row]
print(f"展平的矩阵: {flattened}")

# 条件表达式
numbers = [-2, -1, 0, 1, 2]
abs_numbers = [x if x >= 0 else -x for x in numbers]
print(f"绝对值: {abs_numbers}")

# 字符串处理
sentence = "Hello World Python Programming"
words = sentence.split()
word_lengths = [len(word) for word in words]
print(f"单词长度: {word_lengths}")

# 生成坐标点
coordinates = [(x, y) for x in range(3) for y in range(3)]
print(f"坐标点: {coordinates}")

# 过滤和转换
data = ["1", "2", "abc", "4", "5.5", "def"]
numbers = [float(x) for x in data if x.replace('.', '').isdigit()]
print(f"提取的数字: {numbers}")

字典推导式

# 基本字典推导式
numbers = [1, 2, 3, 4, 5]
square_dict = {x: x ** 2 for x in numbers}
print(f"数字和其平方: {square_dict}")

# 从两个列表创建字典
keys = ["name", "age", "city"]
values = ["Alice", 25, "Beijing"]
person = {k: v for k, v in zip(keys, values)}
print(f"个人信息: {person}")

# 字典过滤和转换
original_dict = {"a": 1, "b": 2, "c": 3, "d": 4}
filtered_dict = {k: v * 2 for k, v in original_dict.items() if v % 2 == 0}
print(f"偶数值翻倍: {filtered_dict}")

# 字符串统计
text = "hello world"
char_count = {char: text.count(char) for char in set(text) if char != ' '}
print(f"字符计数: {char_count}")

# 嵌套字典
students = ["Alice", "Bob", "Charlie"]
subjects = ["Math", "English", "Science"]
grades = {student: {subject: 0 for subject in subjects} for student in students}
print(f"成绩表结构: {grades}")

# 反转字典
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {v: k for k, v in original.items()}
print(f"反转字典: {reversed_dict}")

集合推导式

# 基本集合推导式
numbers = [1, 2, 2, 3, 3, 4, 5]
unique_squares = {x ** 2 for x in numbers}
print(f"唯一平方数: {unique_squares}")

# 字符串处理
sentence = "Hello World Python Programming"
unique_chars = {char.lower() for char in sentence if char.isalpha()}
print(f"唯一字符: {unique_chars}")

# 数学运算
primes_under_20 = {x for x in range(2, 20) if all(x % i != 0 for i in range(2, int(x**0.5) + 1))}
print(f"20以下的质数: {primes_under_20}")

# 集合运算
set1 = {1, 2, 3, 4, 5}
set2 = {4, 5, 6, 7, 8}
common_squares = {x ** 2 for x in set1 if x in set2}
print(f"交集的平方: {common_squares}")

生成器表达式

# 生成器表达式(惰性求值)
numbers = (x ** 2 for x in range(10))
print(f"生成器对象: {numbers}")
print(f"生成器内容: {list(numbers)}")

# 内存效率比较
import sys

# 列表推导式(立即计算)
list_comp = [x ** 2 for x in range(1000)]
print(f"列表推导式内存占用: {sys.getsizeof(list_comp)} 字节")

# 生成器表达式(惰性计算)
gen_exp = (x ** 2 for x in range(1000))
print(f"生成器表达式内存占用: {sys.getsizeof(gen_exp)} 字节")

# 在函数中使用生成器表达式
numbers = range(1, 11)
total = sum(x ** 2 for x in numbers if x % 2 == 0)
print(f"偶数平方和: {total}")

# 链式生成器
def fibonacci():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a + b

# 获取前10个斐波那契数的平方
fib_squares = (x ** 2 for x in fibonacci())
first_10_squares = [next(fib_squares) for _ in range(10)]
print(f"前10个斐波那契数的平方: {first_10_squares}")

# 文件处理生成器
def read_large_file(filename):
    """逐行读取大文件"""
    try:
        with open(filename, 'r', encoding='utf-8') as file:
            for line in file:
                yield line.strip()
    except FileNotFoundError:
        print(f"文件 {filename} 不存在")
        return

# 处理文件内容
filename = "large_file.txt"
with open(filename, 'w', encoding='utf-8') as f:
    for i in range(100):
        f.write(f"这是第{i+1}行\n")

# 使用生成器处理文件
long_lines = (line for line in read_large_file(filename) if len(line) > 10)
for i, line in enumerate(long_lines):
    if i >= 5:  # 只显示前5行
        break
    print(f"长行 {i+1}: {line}")

4.6 综合示例:学生成绩管理系统

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
学生成绩管理系统

功能:
1. 添加学生和成绩
2. 查询学生信息
3. 统计成绩
4. 生成报告

作者: Python学习者
版本: 1.0
"""

import json
import statistics
from typing import Dict, List, Optional, Tuple
from contextlib import contextmanager

class Student:
    """学生类"""
    
    def __init__(self, student_id: str, name: str, age: int):
        self.student_id = student_id
        self.name = name
        self.age = age
        self.grades: Dict[str, float] = {}
    
    def add_grade(self, subject: str, grade: float) -> None:
        """添加成绩"""
        if not 0 <= grade <= 100:
            raise ValueError("成绩必须在0-100之间")
        self.grades[subject] = grade
    
    def get_average(self) -> float:
        """计算平均分"""
        if not self.grades:
            return 0.0
        return statistics.mean(self.grades.values())
    
    def get_grade_level(self) -> str:
        """获取成绩等级"""
        avg = self.get_average()
        if avg >= 90:
            return "优秀"
        elif avg >= 80:
            return "良好"
        elif avg >= 70:
            return "中等"
        elif avg >= 60:
            return "及格"
        else:
            return "不及格"
    
    def to_dict(self) -> dict:
        """转换为字典"""
        return {
            "student_id": self.student_id,
            "name": self.name,
            "age": self.age,
            "grades": self.grades
        }
    
    @classmethod
    def from_dict(cls, data: dict) -> 'Student':
        """从字典创建学生对象"""
        student = cls(data["student_id"], data["name"], data["age"])
        student.grades = data["grades"]
        return student
    
    def __str__(self) -> str:
        return f"学生({self.student_id}): {self.name}, {self.age}岁, 平均分: {self.get_average():.1f}"

class GradeManager:
    """成绩管理器"""
    
    def __init__(self, filename: str = "students.json"):
        self.filename = filename
        self.students: Dict[str, Student] = {}
        self.load_data()
    
    @contextmanager
    def auto_save(self):
        """自动保存上下文管理器"""
        try:
            yield
        finally:
            self.save_data()
    
    def add_student(self, student_id: str, name: str, age: int) -> bool:
        """添加学生"""
        try:
            if student_id in self.students:
                raise ValueError(f"学生ID {student_id} 已存在")
            
            if not name.strip():
                raise ValueError("姓名不能为空")
            
            if not 6 <= age <= 100:
                raise ValueError("年龄必须在6-100之间")
            
            with self.auto_save():
                self.students[student_id] = Student(student_id, name, age)
            
            print(f"成功添加学生: {name}")
            return True
            
        except ValueError as e:
            print(f"添加学生失败: {e}")
            return False
    
    def add_grade(self, student_id: str, subject: str, grade: float) -> bool:
        """添加成绩"""
        try:
            if student_id not in self.students:
                raise ValueError(f"学生ID {student_id} 不存在")
            
            with self.auto_save():
                self.students[student_id].add_grade(subject, grade)
            
            print(f"成功为学生 {student_id} 添加 {subject} 成绩: {grade}")
            return True
            
        except ValueError as e:
            print(f"添加成绩失败: {e}")
            return False
    
    def get_student(self, student_id: str) -> Optional[Student]:
        """获取学生信息"""
        return self.students.get(student_id)
    
    def search_students(self, keyword: str) -> List[Student]:
        """搜索学生"""
        keyword = keyword.lower()
        return [
            student for student in self.students.values()
            if keyword in student.name.lower() or keyword in student.student_id.lower()
        ]
    
    def get_class_statistics(self) -> Dict[str, float]:
        """获取班级统计信息"""
        if not self.students:
            return {}
        
        all_averages = [student.get_average() for student in self.students.values() if student.grades]
        
        if not all_averages:
            return {}
        
        return {
            "班级平均分": statistics.mean(all_averages),
            "最高平均分": max(all_averages),
            "最低平均分": min(all_averages),
            "标准差": statistics.stdev(all_averages) if len(all_averages) > 1 else 0
        }
    
    def get_subject_statistics(self, subject: str) -> Dict[str, float]:
        """获取科目统计信息"""
        grades = [
            student.grades[subject] for student in self.students.values()
            if subject in student.grades
        ]
        
        if not grades:
            return {}
        
        return {
            "平均分": statistics.mean(grades),
            "最高分": max(grades),
            "最低分": min(grades),
            "及格率": len([g for g in grades if g >= 60]) / len(grades) * 100
        }
    
    def generate_report(self) -> str:
        """生成报告"""
        report = ["\n" + "=" * 50]
        report.append("           学生成绩报告")
        report.append("=" * 50)
        
        # 学生总数
        report.append(f"学生总数: {len(self.students)}")
        
        # 班级统计
        class_stats = self.get_class_statistics()
        if class_stats:
            report.append("\n班级统计:")
            for key, value in class_stats.items():
                report.append(f"  {key}: {value:.2f}")
        
        # 各等级人数统计
        grade_levels = {"优秀": 0, "良好": 0, "中等": 0, "及格": 0, "不及格": 0}
        for student in self.students.values():
            if student.grades:
                level = student.get_grade_level()
                grade_levels[level] += 1
        
        report.append("\n成绩等级分布:")
        for level, count in grade_levels.items():
            percentage = count / len(self.students) * 100 if self.students else 0
            report.append(f"  {level}: {count}人 ({percentage:.1f}%)")
        
        # 科目统计
        all_subjects = set()
        for student in self.students.values():
            all_subjects.update(student.grades.keys())
        
        if all_subjects:
            report.append("\n科目统计:")
            for subject in sorted(all_subjects):
                stats = self.get_subject_statistics(subject)
                if stats:
                    report.append(f"  {subject}:")
                    report.append(f"    平均分: {stats['平均分']:.2f}")
                    report.append(f"    最高分: {stats['最高分']:.1f}")
                    report.append(f"    最低分: {stats['最低分']:.1f}")
                    report.append(f"    及格率: {stats['及格率']:.1f}%")
        
        # 优秀学生
        excellent_students = [
            student for student in self.students.values()
            if student.grades and student.get_average() >= 90
        ]
        
        if excellent_students:
            report.append("\n优秀学生 (平均分≥90):")
            for student in sorted(excellent_students, key=lambda s: s.get_average(), reverse=True):
                report.append(f"  {student.name} ({student.student_id}): {student.get_average():.1f}分")
        
        report.append("=" * 50)
        return "\n".join(report)
    
    def save_data(self) -> None:
        """保存数据到文件"""
        try:
            data = {sid: student.to_dict() for sid, student in self.students.items()}
            with open(self.filename, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception as e:
            print(f"保存数据失败: {e}")
    
    def load_data(self) -> None:
        """从文件加载数据"""
        try:
            with open(self.filename, 'r', encoding='utf-8') as f:
                data = json.load(f)
                self.students = {
                    sid: Student.from_dict(student_data)
                    for sid, student_data in data.items()
                }
        except FileNotFoundError:
            print(f"数据文件 {self.filename} 不存在,将创建新文件")
        except Exception as e:
            print(f"加载数据失败: {e}")

def main():
    """主函数"""
    manager = GradeManager()
    
    while True:
        print("\n" + "=" * 30)
        print("    学生成绩管理系统")
        print("=" * 30)
        print("1. 添加学生")
        print("2. 添加成绩")
        print("3. 查询学生")
        print("4. 搜索学生")
        print("5. 生成报告")
        print("6. 退出")
        
        try:
            choice = input("\n请选择操作 (1-6): ").strip()
            
            if choice == '1':
                student_id = input("请输入学生ID: ").strip()
                name = input("请输入姓名: ").strip()
                age = int(input("请输入年龄: "))
                manager.add_student(student_id, name, age)
            
            elif choice == '2':
                student_id = input("请输入学生ID: ").strip()
                subject = input("请输入科目: ").strip()
                grade = float(input("请输入成绩: "))
                manager.add_grade(student_id, subject, grade)
            
            elif choice == '3':
                student_id = input("请输入学生ID: ").strip()
                student = manager.get_student(student_id)
                if student:
                    print(f"\n{student}")
                    if student.grades:
                        print("各科成绩:")
                        for subject, grade in student.grades.items():
                            print(f"  {subject}: {grade}")
                        print(f"成绩等级: {student.get_grade_level()}")
                    else:
                        print("暂无成绩记录")
                else:
                    print("学生不存在")
            
            elif choice == '4':
                keyword = input("请输入搜索关键字: ").strip()
                students = manager.search_students(keyword)
                if students:
                    print(f"\n找到 {len(students)} 个学生:")
                    for student in students:
                        print(f"  {student}")
                else:
                    print("未找到匹配的学生")
            
            elif choice == '5':
                report = manager.generate_report()
                print(report)
                
                # 询问是否保存报告
                save_report = input("\n是否保存报告到文件? (y/n): ").lower().strip()
                if save_report in ['y', 'yes', '是']:
                    with open("grade_report.txt", 'w', encoding='utf-8') as f:
                        f.write(report)
                    print("报告已保存到 grade_report.txt")
            
            elif choice == '6':
                print("感谢使用学生成绩管理系统!")
                break
            
            else:
                print("无效的选择,请重新输入")
        
        except ValueError as e:
            print(f"输入错误: {e}")
        except KeyboardInterrupt:
            print("\n\n程序被用户中断")
            break
        except Exception as e:
            print(f"发生错误: {e}")

if __name__ == "__main__":
    # 添加一些测试数据
    manager = GradeManager()
    
    # 添加测试学生
    test_students = [
        ("001", "张三", 20),
        ("002", "李四", 19),
        ("003", "王五", 21),
        ("004", "赵六", 20)
    ]
    
    for sid, name, age in test_students:
        manager.add_student(sid, name, age)
    
    # 添加测试成绩
    test_grades = [
        ("001", "数学", 95),
        ("001", "英语", 88),
        ("001", "物理", 92),
        ("002", "数学", 78),
        ("002", "英语", 85),
        ("002", "物理", 80),
        ("003", "数学", 65),
        ("003", "英语", 70),
        ("003", "物理", 68),
        ("004", "数学", 58),
        ("004", "英语", 62),
        ("004", "物理", 55)
    ]
    
    for sid, subject, grade in test_grades:
        manager.add_grade(sid, subject, grade)
    
    # 启动主程序
    main()

运行成绩管理系统:

python grade_manager.py

本章小结

本章我们学习了Python的控制结构:

  1. 条件语句:if/elif/else语句、条件表达式、复杂条件判断
  2. 循环语句:for循环、while循环、循环控制语句
  3. 异常处理:try/except/finally、自定义异常、异常处理最佳实践
  4. 上下文管理器:with语句、自定义上下文管理器
  5. 推导式:列表、字典、集合推导式、生成器表达式
  6. 综合应用:通过学生成绩管理系统整合所学知识

下一章预告

下一章我们将学习《数据结构》,内容包括: - 列表的高级操作 - 元组和命名元组 - 字典的高级用法 - 集合操作 - 字符串的深入应用

练习题

基础练习

  1. 条件判断

    • 编写程序判断一个年份是否为闰年
    • 实现简单的计算器(支持四则运算)
    • 编写程序判断三角形的类型(等边、等腰、普通)
  2. 循环练习

    • 使用for循环打印九九乘法表
    • 编写程序计算1到100的质数
    • 实现猜数字游戏

进阶练习

  1. 异常处理

    • 编写安全的文件读写函数
    • 实现带重试机制的网络请求模拟
    • 创建自定义异常类处理业务逻辑错误
  2. 推导式

    • 使用列表推导式处理嵌套列表
    • 用字典推导式统计文本中的词频
    • 实现生成器函数处理大数据

综合练习

  1. 项目实战
    • 扩展学生成绩管理系统,添加更多功能
    • 实现简单的图书管理系统
    • 创建命令行版本的待办事项管理器

提示:控制结构是编程的核心,多练习不同场景下的应用,培养逻辑思维能力。