3.4嵌套数据结构与深拷贝

102 阅读3分钟

Python嵌套数据与深拷贝实战:学生成绩系统设计

# 快速导航
student_template = {
    "info": {"name": "", "id": ""},
    "scores": {"math": [], "english": []}
}

一、嵌套数据结构解析

1. 常见嵌套结构示例

# 列表嵌套字典
class_1A = [
    {"name": "张三", "scores": {"数学": 85, "英语": 92}},
    {"name": "李四", "scores": {"数学": 78, "英语": 88}}
]
​
# 字典嵌套列表
course_db = {
    "math": {
        "students": ["张三", "李四"],
        "scores": [85, 78]
    },
    "english": {
        "students": ["张三", "李四"],
        "scores": [92, 88]
    }
}

2. 数据访问模式

# 多层访问
print(class_1A[0]["scores"]["数学"])  # 85

# 动态键值访问
subject = "英语"
print(class_1A[1]["scores"].get(subject, "未录入"))  # 88

# 复杂数据遍历
for student in class_1A:
    print(f"{student['name']} 平均分:{sum(student['scores'].values())/len(student['scores']):.1f}")

嵌套结构选择指南

  • 需要顺序访问 → 列表嵌套
  • 需要快速查找 → 字典嵌套
  • 混合结构 → 字典包含列表值
  • 树形结构 → 递归嵌套字典

二、深浅拷贝核心解析

1. 浅拷贝陷阱演示

import copy

original = [[1,2], [3,4]]
shallow_copy = copy.copy(original)

original[0][0] = 99
print(shallow_copy)  # [[99,2], [3,4]] → 内层列表被修改

2. 深拷贝解决方案

deep_copy = copy.deepcopy(original)
original[1][1] = 88
print(deep_copy)  # [[99,2], [3,4]] → 保持独立

拷贝方式对比表

特性赋值操作浅拷贝深拷贝
创建新对象✔️✔️
复制嵌套对象✔️
内存占用最小中等最大
适用场景引用传递简单结构复杂嵌套

三、学生成绩系统实战

1. 数据结构设计

from dataclasses import dataclass
from typing import Dict, List

@dataclass
class Student:
    id: str
    name: str
    scores: Dict[str, List[float]]  # 课程: [成绩列表]
    credit: float = 0.0

class GradeSystem:
    def __init__(self):
        self.students = {}  # {学号: Student对象}
        self.courses = ["数学", "英语", "编程"]

2. 核心功能实现

    def add_score(self, stu_id: str, course: str, score: float):
        """添加单科成绩"""
        student = self.students[stu_id]
        if course not in student.scores:
            student.scores[course] = []
        student.scores[course].append(score)
        self._update_credit(stu_id)

    def _update_credit(self, stu_id: str):
        """学分计算逻辑"""
        student = self.students[stu_id]
        total = 0
        for course, scores in student.scores.items():
            avg = sum(scores) / len(scores)
            total += avg * 2  # 假设每学分对应2个课时
        student.credit = total

    def get_student_copy(self, stu_id: str) -> Student:
        """获取学生数据的深拷贝"""
        return copy.deepcopy(self.students[stu_id])

3. 使用示例

# 初始化系统
system = GradeSystem()

# 添加学生
system.students["001"] = Student(
    id="001",
    name="王小明",
    scores={"数学": [85, 90], "英语": [92]}
)

# 添加新成绩
system.add_score("001", "编程", 88)

# 安全获取副本
student_copy = system.get_student_copy("001")
student_copy.scores["数学"].append(95)  # 修改副本不影响原数据

四、最佳实践与性能优化

1. 拷贝策略指南

# 需要深拷贝的情况
config = {
    "thresholds": {"pass": 60, "excellent": 90},
    "rules": ["允许补考", "成绩加权"]
}

# 优化方案:部分深拷贝
safe_config = {
    "thresholds": copy.deepcopy(config["thresholds"]),
    "rules": config["rules"].copy()  # 列表浅拷贝
}

2. 替代深拷贝方案

# 使用不可变类型
ImmutableStudent = namedtuple('Student', ['id', 'name', 'scores'])

# JSON序列化方案
import json
safe_copy = json.loads(json.dumps(original_data))

性能优化技巧

  • 使用__slots__减少对象内存占用
  • 对频繁拷贝的数据进行结构扁平化
  • 按需拷贝(仅拷贝变化部分)
  • 使用缓存机制减少拷贝次数

扩展思考

  1. 如何设计支持版本回溯的成绩修改历史系统?
  2. 当数据结构包含自定义对象时如何处理深拷贝?
  3. 使用WeakRef实现数据缓存时需要注意什么?
  4. 如何利用结构共享(Persistent Data Structures)优化深拷贝性能?

下节预告:面向对象编程进阶——实现自定义数据结构的魔法方法