软件工程第三次作业-结对项目
| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/ |
|---|---|
| 这个作业要求在哪里 | https://edu.cnblogs.com/campus/gdgy/Class12Grade23ComputerScience/homework/13470 |
| 这个作业的目标 | 完成一个自动生成小学四则运算题目的命令行程序 |
| 项目 | 姓名 | 学号 |
|---|---|---|
| 成员1 | 陈曦 | 3223004210 |
| 成员2 | 白子璇 | 3223004208 |
Github项目地址:https://github.com/Echooooe/Echooooe/tree/main/结对项目
1.PSP表格(预计时间)
| PSP2.1 | Personal Software Process Stages | 预估耗时 (分钟) | 实际耗时 (分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | |
| Estimate | 估计这个任务需要多少时间 | 200 | |
| Development | 开发 | 120 | |
| Analysis | 需求分析 (包括学习新技术) | 50 | |
| Design Spec | 生成设计文档 | 40 | |
| Design Review | 设计复审 | 15 | |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 15 | |
| Design | 具体设计 | 50 | |
| Coding | 具体编码 | 200 | |
| Code Review | 代码复审 | 40 | |
| Test | 测试(自我测试,修改代码,提交修改) | 50 | |
| Reporting | 报告 | 90 | |
| Test Repor | 测试报告 | 50 | |
| Size Measurement | 计算工作量 | 30 | |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | |
| 合计 | 1010 |
2.性能分析
优化前:
生成大量题目时-n 5000 查看程序最耗时的部分
cprofile:
Welcome to the profile statistics browser.
result.prof% sort cumulative
result.prof% stats 20
Thu Oct 16 10:41:01 2025 result.prof
1717145 function calls (1663174 primitive calls) in 2.168 seconds
Ordered by: cumulative time
List reduced from 396 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
13/1 0.000 0.000 2.168 2.168 {built-in method builtins.exec}
1 0.001 0.001 2.168 2.168 Myapp.py:1(<module>)
1 0.010 0.010 2.137 2.137 Myapp.py:390(main)
1 0.069 0.069 2.084 2.084 Myapp.py:231(generate_exercises)
5765 0.199 0.000 1.289 0.000 Myapp.py:190(gen_expr_with_ops)
17365 0.102 0.000 0.394 0.000 Myapp.py:143(gen_number)
10746/5765 0.049 0.000 0.287 0.000 Myapp.py:128(canonical)
38182 0.145 0.000 0.287 0.000 Myapp.py:261(format_fraction_output)
33182 0.032 0.000 0.271 0.000 Myapp.py:55(to_str)
12474 0.078 0.000 0.248 0.000 D:\Software\miniconda\Lib\random.py:359(sample)
31134 0.047 0.000 0.230 0.000 D:\Software\miniconda\Lib\fractions.py:613(forward)
33537 0.037 0.000 0.229 0.000 D:\Software\miniconda\Lib\random.py:332(randint)
10817/5000 0.062 0.000 0.218 0.000 Myapp.py:95(to_str)
5765 0.014 0.000 0.212 0.000 Myapp.py:162(validate_tree)
141894 0.077 0.000 0.199 0.000 {built-in method builtins.isinstance}
28965/5765 0.071 0.000 0.197 0.000 Myapp.py:167(dfs)
70959 0.128 0.000 0.194 0.000 D:\Software\miniconda\Lib\random.py:242(_randbelow_with_getrandbits)
33537 0.075 0.000 0.192 0.000 D:\Software\miniconda\Lib\random.py:291(randrange)
16505/9685 0.046 0.000 0.171 0.000 Myapp.py:70(eval)
17365 0.014 0.000 0.170 0.000 Myapp.py:59(canonical)
pstats性能报告:

| 函数 | ncalls | cumtime (s) | 占比 | 说明 |
|---|---|---|---|---|
gen_expr_with_ops |
5,765 | 1.289 | 59.4% | 核心表达式生成逻辑,递归随机组合节点,验证合法性 |
gen_number |
17,365 | 0.394 | 18% | 随机生成自然数/分数/带分数 |
format_fraction_output |
38,182 | 0.287 | 13% | 将 Fraction 转成字符串,包括带分数和真分数 |
canonical |
10,746 / 17,365 | 0.287 / 0.170 | 约 12% | 去重标准化字符串(对 +/* 做排序归一化) |
dfs |
28,965 / 5,765 | 0.197 | 约 9% | validate_tree 中递归判断表达式合法性 |
当前性能瓶颈主要集中在:
(1) gen_expr_with_ops(最大瓶颈)
- 占总耗时 >50%,原因:
- 每次生成表达式,需要在节点池中随机取两个节点组合;
- 每次随机组合后都要检查 减法/除法合法性;
- 重复尝试的次数很多(
MAX_TRIES=20000),容易产生大量无效组合; dfs和validate_tree被反复调用,导致递归计算多次。
(2) gen_number(次大瓶颈)
- 占用约 18%,原因:
- 每生成一个节点都会调用多次
random.randint(),分数/带分数的生成逻辑复杂,涉及整数和分母随机选择; - 重复计算和条件判断较多。
- 每生成一个节点都会调用多次
(3) format_fraction_output / canonical
- 占用约 12%-13%,原因:
Fraction转字符串、带分数判断和拼接耗时;- canonical 需要对 +/* 运算符的子节点排序,频繁调用
to_str()。
优化思路:
对gen_expr_with_ops函数:
1.缓存叶子节点值 → 避免重复 eval() 调用。
2.randrange 代替 sample → 减少随机索引生成开销。
3.提前剪枝非法组合 → 不生成不合法节点,减少无用操作。
4.最终一次性验证 → 避免重复 dfs 验证,提高效率。
优化后:
cprofile:
1769853 function calls (1717355 primitive calls) in 1.908 seconds
Ordered by: cumulative time
List reduced from 394 to 20 due to restriction <20>
ncalls tottime percall cumtime percall filename:lineno(function)
13/1 0.000 0.000 1.908 1.908 {built-in method builtins.exec}
1 0.000 0.000 1.908 1.908 Myapp.py:1(<module>)
1 0.016 0.016 1.877 1.877 Myapp.py:407(main)
1 0.065 0.065 1.817 1.817 Myapp.py:248(generate_exercises)
5783 0.203 0.000 1.125 0.000 Myapp.py:190(gen_expr_with_ops)
17355 0.090 0.000 0.356 0.000 Myapp.py:143(gen_number)
67407 0.113 0.000 0.314 0.000 D:\Software\miniconda\Lib\random.py:291(randrange)
10702/5783 0.045 0.000 0.241 0.000 Myapp.py:128(canonical)
38118 0.109 0.000 0.241 0.000 Myapp.py:278(format_fraction_output)
33118 0.027 0.000 0.224 0.000 Myapp.py:55(to_str)
34630 0.048 0.000 0.219 0.000 D:\Software\miniconda\Lib\fractions.py:613(forward)
33485 0.035 0.000 0.216 0.000 D:\Software\miniconda\Lib\random.py:332(randint)
79887 0.128 0.000 0.197 0.000 D:\Software\miniconda\Lib\random.py:242(_randbelow_with_getrandbits)
10763/5000 0.045 0.000 0.185 0.000 Myapp.py:95(to_str)
5783 0.011 0.000 0.185 0.000 Myapp.py:162(validate_tree)
28927/5783 0.066 0.000 0.174 0.000 Myapp.py:167(dfs)
30146 0.027 0.000 0.167 0.000 D:\Software\miniconda\Lib\fractions.py:953(__lt__)
17355 0.019 0.000 0.140 0.000 Myapp.py:59(canonical)
30146 0.053 0.000 0.140 0.000 D:\Software\miniconda\Lib\fractions.py:931(_richcmp)
133885 0.061 0.000 0.103 0.000 {built-in method builtins.isinstance}
pstats性能报告:

改进前后性能分析结果对比
| 指标 | 优化前 | 优化后 | 变化 |
|---|---|---|---|
| 总函数调用数 | 1,717,145 | 1,769,853 | ↑ +3.1%(轻微增加) |
| 运行总时长 | 2.168 s | 1.908 s | ↓ 12% 加速 |
gen_expr_with_ops() 耗时 |
1.289 s | 1.125 s | ↓ 12.7% 加速 |
gen_number() 耗时 |
0.394 s | 0.356 s | ↓ 9.6% |
format_fraction_output() 耗时 |
0.287 s | 0.241 s | ↓ 16% |
主函数 generate_exercises() 总耗时 |
2.084 s | 1.817 s | ↓ 12.8% |
3.设计实现过程
(1)类和函数设计
①类结构设计
| 类名 | 作用 | 主要方法 | 说明 |
|---|---|---|---|
Expr |
抽象基类 | eval()、to_str()、canonical() |
定义表达式统一接口,所有子类继承 |
Number |
数字节点类 | eval()、to_str() |
存储单个数值(自然数或分数) |
Binary |
二元运算类 | eval()、to_str()、canonical() |
存储加、减、乘、除等二叉表达式 |
②类的继承结构

③主要函数设计
| 函数名 | 功能 | 说明 |
|---|---|---|
gen_number(rng) |
生成随机自然数或真分数 | 作为表达式叶节点 |
validate_tree(node) |
验证表达式合法性 | 检查负数、整除、除零 |
gen_expr_with_ops(k, rng) |
生成包含 k 个运算符的表达式 | 随机生成 + 递归拼接 |
generate_exercises(n, rng) |
批量生成题目与答案 | 调用上层函数并去重 |
grade(exfile, ansfile) |
比较标准答案与用户答案 | 输出 Grade.txt 批改结果 |
parse_and_eval(s) |
解析字符串表达式并求值 | 支持 ÷、带分数格式 |
format_fraction_output(fr) |
将 Fraction 格式化输出 | 生成整数、分数、带分数形式 |
parse_mixed_fraction(s) |
将“2'3/4”等字符串转 Fraction | 解析带分数格式 |
generate() |
GUI按钮回调,生成题目文件 | 调用 generate_exercises() |
grade_files() |
GUI按钮回调,批改文件 | 调用 grade() 并弹窗提示 |
(2)关键函数流程图

4.代码说明
关键代码与注释说明
(1)表达式类设计(Expr、Number、Binary)
Expr:
class Expr:
"""表达式抽象基类"""
def eval(self) -> Fraction:
"""计算表达式结果"""
raise NotImplementedError
def to_str(self) -> str:
"""将表达式转换为可显示字符串"""
raise NotImplementedError
def canonical(self) -> str:
"""生成用于去重的标准化字符串"""
raise NotImplementedError
思路说明:该类是所有表达式的抽象父类;提供统一接口 eval()(求值)、to_str()(转字符串)、canonical()(标准化形式);子类 Number 与 Binary 继承并实现这些方法。
Number:
class Number(Expr):
"""表示一个数值节点(自然数或分数)"""
def __init__(self, frac: Fraction):
self.frac = frac
def eval(self):
return self.frac
def to_str(self):
"""将 Fraction 转换为字符串形式"""
return format_fraction_output(self.frac)
思路说明:Number 是表达式树的叶子节点;直接存储一个 Fraction(分数或整数);eval() 直接返回该分数的值;to_str() 用于输出可读格式(如 1'1/2)。
Binary:
class Binary(Expr):
"""表示二元运算节点(+ - * /)"""
def __init__(self, op, left: Expr, right: Expr):
self.op = op
self.left = left
self.right = right
def eval(self):
"""递归计算表达式结果"""
a = self.left.eval()
b = self.right.eval()
if self.op == '+': return a + b
if self.op == '-': return a - b
if self.op == '*': return a * b
if self.op == '/': return a / b
思路说明:Binary 是二叉树节点,包含运算符和左右子表达式;eval() 递归调用左右子树的 eval();运算均用 Fraction 保持精度;支持加、减、乘、除四种操作。
(2)随机题目生成模块
gen_number:
def gen_number(rng):
"""生成随机数字(自然数或真分数)"""
if random.random() < 0.5:
return Number(Fraction(random.randint(0, rng - 1), 1))
else:
denom = random.randint(2, rng)
numer = random.randint(1, denom - 1)
return Number(Fraction(numer, denom))
思路说明:以随机方式生成一个数字节点;一半概率生成整数,一半生成真分数;用 Python 内置的 Fraction 保证计算精度。
gen_expr_with_ops:
def gen_expr_with_ops(k, rng):
"""生成包含 k 个运算符的随机表达式"""
leaves = [gen_number(rng) for _ in range(k + 1)]
nodes = leaves[:]
while len(nodes) > 1:
left = random.choice(nodes)
right = random.choice(nodes)
if left == right:
continue
op = random.choice(['+', '-', '*', '/'])
node = Binary(op, left, right)
if not validate_tree(node): # 确保合法性
continue
nodes.remove(left)
nodes.remove(right)
nodes.append(node)
return nodes[0]
思路说明:通过随机组合数字节点构造表达式树;每次合并两个节点成一个新的 Binary;生成过程中实时调用 validate_tree() 检查合法性,防止出现负数、除零、整除等非法情况。
generate_exercises:
def generate_exercises(n, rng):
"""生成 n 道符合约束的题目与答案"""
exercises, answers, seen = [], [], set()
while len(exercises) < n:
k = random.randint(1, 3)
root = gen_expr_with_ops(k, rng)
if not root:
continue
can = root.canonical()
if can in seen: # 去重
continue
seen.add(can)
exercises.append(root.to_str() + ' =')
answers.append(format_fraction_output(root.eval()))
return exercises, answers
思路说明:负责批量生成题目;随机选运算符数量(1~3);用 canonical() 确保等价表达式不会重复;输出题目字符串与正确答案列表。
(3)表达式合法性检查
def validate_tree(node: Expr) -> bool:
"""验证表达式是否合法"""
try:
def dfs(n):
if isinstance(n, Number):
return n.eval()
a = dfs(n.left)
b = dfs(n.right)
if n.op == '-':
if a < b: raise ValueError('negative')
return a - b
if n.op == '/':
if b == 0: raise ValueError('divzero')
res = a / b
if res.denominator == 1: # 排除整除
raise ValueError('div_integer')
return res
if n.op == '+': return a + b
if n.op == '*': return a * b
dfs(node)
return True
except Exception:
return False
思路说明:递归遍历表达式树;检查是否出现负数、除零或整除结果;如果违反条件则返回 False,确保生成的题目合法、符合小学题型要求。
(4)批改逻辑
def grade(exfile, ansfile):
"""读取题目与答案文件,逐题比对,输出 Grade.txt"""
with open(exfile, 'r', encoding='utf-8') as f:
exercises = [line.strip() for line in f if line.strip()]
with open(ansfile, 'r', encoding='utf-8') as f:
answers = [line.strip() for line in f if line.strip()]
correct_idx, wrong_idx = [], []
for i in range(min(len(exercises), len(answers))):
expr_text = strip_number_prefix(exercises[i])[:-1].strip()
got = parse_and_eval(expr_text) # 正确结果
ans_val = parse_and_eval(answers[i]) # 用户答案
if got == ans_val:
correct_idx.append(i + 1)
else:
wrong_idx.append(i + 1)
with open('Grade.txt', 'w', encoding='utf-8') as f:
f.write(f"Correct: {len(correct_idx)} ({', '.join(map(str, correct_idx))})\n\n")
f.write(f"Wrong: {len(wrong_idx)} ({', '.join(map(str, wrong_idx))})\n")
print('Grade.txt 已生成')
思路说明:逐题对比用户答案与标准答案;使用 parse_and_eval() 计算正确值;比较结果相等即为正确,最终输出统计结果文件 Grade.txt,显示正确和错误题号。
(5)表达式解析函数
def parse_and_eval(s: str) -> Fraction:
"""解析字符串表达式并计算结果"""
s = s.replace('÷', '/')
tokens = TOKEN_REGEX.findall(s.replace(' ', ''))
out_tokens = []
for tok in tokens:
if '/' in tok and tok[0].isdigit():
n, d = tok.split('/')
out_tokens.append(f'Fraction({int(n)},{int(d)})')
elif tok.isdigit():
out_tokens.append(f'Fraction({int(tok)},1)')
else:
out_tokens.append(tok)
expr = ''.join(out_tokens)
val = eval(expr, {'Fraction': Fraction})
return val
思路说明:将字符串形式的算式(如 "3 ÷ 2 + 1/4") 转换为 Python 可执行表达式;将分数、带分数转换为 Fraction,最终用 eval() 在安全上下文中求值,返回一个精确分数结果。
(6)分数格式化输出
def format_fraction_output(fr: Fraction) -> str:
"""将 Fraction 格式化为输出形式"""
if fr.denominator == 1:
return str(fr.numerator)
n, d = abs(fr.numerator), fr.denominator
if n > d:
whole, rem = n // d, n % d
sign = '-' if fr < 0 else ''
return f"{sign}{whole}'{rem}/{d}"
sign = '-' if fr < 0 else ''
return f"{sign}{n}/{d}"
思路说明:输出整数、真分数或带分数;
例如:Fraction(5,1) → "5";Fraction(3,2) → "1'1/2";Fraction(-7,3) → "-2'1/3";
保持输出格式统一,方便小学生理解。
5.扩展功能
(1)设计思路
我们在原有命令行系统的基础上开发了图形化界面(Myapp_gui.py)。GUI 基于tkinter实现,用户可通过界面选择模式、输入参数、生成题目或批改结果,无需手动操作文件或命令行。
整个设计采用 逻辑层与界面层分离 思想:
- 逻辑层(Myapp.py):提供核心算法与函数,如 generate_exercises()、grade()。
- 界面层(Myapp_gui.py):负责交互操作与结果显示。
- GUI 直接调用逻辑层函数,实现“图形化封装”的效果。
(2)关键代码片段与说明
① 主窗口与布局创建
root = tk.Tk()
root.title("小学四则运算生成与批改系统")
root.geometry("500x350")
frame_generate = tk.LabelFrame(root, text="生成题目")
frame_generate.pack(fill="x", padx=10, pady=10)
frame_grade = tk.LabelFrame(root, text="批改答案")
frame_grade.pack(fill="x", padx=10, pady=10)
说明:
- 创建主窗口与两个功能分区(题目生成区与批改区);
- 采用 LabelFrame 使界面层次清晰;
- pack() 布局方式保证窗口自适应缩放。
② 生成题目
def generate():
n = int(entry_num.get())
rng = int(entry_range.get())
exercises, answers = Myapp.generate_exercises(n, rng)
with open("Exercises.txt", "w") as f1, open("Answers.txt", "w") as f2:
for i in range(n):
f1.write(f"{i + 1}. {exercises[i]}\n")
f2.write(f"{i + 1}. {answers[i]}\n")
messagebox.showinfo("生成成功", "题目与答案已生成!")
说明:
- 从输入框中读取题目数量与数值范围;
- 调用逻辑层 generate_exercises() 生成内容,自动保存到 Exercises.txt 与 Answers.txt;
- 用 messagebox 弹窗提示执行结果。
③ 批改答案
def grade():
exfile = entry_exfile.get()
ansfile = entry_ansfile.get()
Myapp.grade(exfile, ansfile)
messagebox.showinfo("批改完成", "结果已生成 Grade.txt!")
说明:
- 通过文件选择框选择题目文件与答案文件;
- 调用逻辑层 grade() 完成自动批改,结果保存在 Grade.txt,并提示完成。
④ 文件选择
def select_file(entry):
path = filedialog.askopenfilename(title="选择文件", filetypes=[("Text Files", "*.txt")])
entry.delete(0, tk.END)
entry.insert(0, path)
说明:
- 封装文件选择对话框;
- 用户无需手动输入文件路径,防止路径错误或找不到文件的问题。
(3)运行界面展示
①生成题目界面


②文件选择界面

③成功批改答案并生成Grade.txt

6.测试运行
测试用例
| 序号 | 测试函数名 | 测试目标 | 测试思路 |
|---|---|---|---|
| 1 | test_gen_number |
验证 gen_number 能否正确生成 Number 对象且值为 Fraction |
随机生成 50 个 Number,检查类型与 eval() 输出类型 |
| 2 | test_number_eval |
验证 Number.eval() 返回自身存储的 Fraction |
构造一个 Number(Fraction),调用 eval() 并与原 Fraction 比较 |
| 3 | test_binary_eval |
验证 Binary.eval() 正确计算加法结果 |
构造 Binary('+', Number, Number),检查 eval() 与手动计算结果一致 |
| 4 | test_gen_expr_with_ops_valid |
验证 gen_expr_with_ops 能生成合法表达式 |
生成最多 3 个运算符的表达式,检查对象类型并用 validate_tree 验证合法性 |
| 5 | test_validate_tree_negative |
验证 validate_tree 能检测减法产生负数的非法情况 |
构造 1 - 2,断言 validate_tree 返回 False |
| 6 | test_validate_tree_div_integer |
验证 validate_tree 能检测除法结果为整数的非法情况 |
构造 4 ÷ 2,结果分母为 1,断言 validate_tree 返回 False |
| 7 | test_format_fraction_output |
验证 format_fraction_output 能正确格式化整数、真分数、带分数和负数 |
构造多种 Fraction,检查输出字符串是否符合预期 |
| 8 | test_parse_mixed_fraction |
验证 parse_mixed_fraction 能解析带分数、真分数和整数 |
输入 "3'2/5", "2/3", "5",检查返回的 Fraction 是否正确 |
| 9 | test_parse_and_eval |
验证 parse_and_eval 能正确解析题目字符串并返回 Fraction,支持带分数和 ÷ 符号 |
构造加法、带分数加法、除法表达式,检查计算结果是否正确 |
| 10 | test_generate_exercises_count_and_unique |
验证 generate_exercises 能生成指定数量的题目和答案,题目去重生效 |
生成 10 道题目,检查题目和答案长度是否一致,并解析表达式确保值非空 |
测试结果

7.PSP表格(实际时间)
| PSP2.1 | Personal Software Process Stages | 预估耗时 (分钟) | 实际耗时 (分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 30 |
| Estimate | 估计这个任务需要多少时间 | 200 | 300 |
| Development | 开发 | 120 | 100 |
| Analysis | 需求分析 (包括学习新技术) | 50 | 30 |
| Design Spec | 生成设计文档 | 40 | 30 |
| Design Review | 设计复审 | 15 | 15 |
| Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 15 | 15 |
| Design | 具体设计 | 50 | 50 |
| Coding | 具体编码 | 200 | 150 |
| Code Review | 代码复审 | 40 | 30 |
| Test | 测试(自我测试,修改代码,提交修改) | 50 | 60 |
| Reporting | 报告 | 90 | 80 |
| Test Repor | 测试报告 | 50 | 50 |
| Size Measurement | 计算工作量 | 30 | 20 |
| Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 30 | 30 |
| 合计 | 1010 | 990 |
8.commit记录:

9.项目小结
(1)项目概述
本次结对项目的主题是 《小学四则运算题目生成与批改系统》。项目包含命令行与图形化界面(GUI)两种模式,支持题目自动生成、答案批改与结果统计。我们采用 Python + tkinter 技术栈,通过 Fraction 模块保证分数计算精度,并实现了题目合法性校验、去重、异常处理等功能。
(2)项目总结
| 方面 | 成功经验 | 不足与改进方向 |
|---|---|---|
| 功能实现 | 成功实现题目生成、答案文件生成、自动批改、结果输出等完整流程。 | 题目难度层次较单一,后续可扩展多级难度或自定义运算符数。 |
| 程序设计 | 采用模块化设计,结构清晰。 | 代码可进一步封装为类体系,如独立的 ExerciseGenerator 类。 |
| 测试与验证 | 使用 pytest 进行单元测试,验证表达式、分数格式与批改逻辑。 |
GUI 层暂未进行自动化测试,可后续补充。 |
| 团队协作 | 明确分工,沟通顺畅,能互相检查代码与报告。 | 时间安排略紧,有些文档部分未能同步修改。 |
总体而言,项目目标完成度高、系统运行稳定,是一次成功的结对开发实践。
(3)结对开发感受
本次结对开发让我们深刻体会到两人合作编程的乐趣与挑战。当一方负责编码、另一方进行测试时,能够迅速发现逻辑漏洞;讨论设计思路的过程比单独写代码更能激发灵感;共同解决 Bug 的过程也增强了团队协作意识。我们在合作中实现了互补:一方更擅长算法逻辑,另一方更擅长界面与用户体验,使项目最终效果更完整。
(4)建议分享
| 成员 | 闪光点 | 改进建议 |
|---|---|---|
| 成员1(主要负责逻辑与测试) | 代码思路清晰,逻辑结构强,注重算法正确性。 | 可在 GUI 部分投入更多参与,以更好理解整体流程。 |
| 成员2(主要负责界面与文档) | 界面设计美观、交互友好,报告文档规范。 | 可进一步加强 Python 数据结构与函数式编程理解。 |

浙公网安备 33010602011771号