基于python的结对作业

news/2024/9/28 15:38:28

github项目地址

这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34
这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230
团队成员1 何昌洲 3122004737
团队成员2 郑玮源 3122004760
这个作业的目标 用python语言结对合作完成小学四则运算题目的程序,提高项目合作能力

一、PSP表格

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

二、运行环境

IDE:PyCharm 2024.1.4

三、核心函数设计

流程图

一、程序分析

程序实现了以下主要功能:

1.带分数处理函数

  • mixed_to_fraction(mixed_str): 这个函数将带分数(如1'1/2)或普通分数(如3/4)转换为 fractions.Fraction 对象,以方便后续的精确计算。
  • fraction_to_mixed(f): 将分数转换为带分数的格式(如 7/3 转换为 2'1/3),以便结果能以更友好的形式呈现。

2.生成随机数和真分数

  • generate_number(range_limit): 这个函数根据给定的范围生成随机的自然数或分数。为了避免分母为零的情况,特别地在生成分数时,确保分母不为0,且分子和分母的组合不整除,以保证生成的是真分数。

3.表达式计算

  • eval_expression(expr): 通过将输入表达式中的带分数和普通分数字符串转换为 Fraction 对象,然后使用 eval 函数来计算表达式的值。表达式中的除法使用÷符号,eval 会将其替换为标准的除法运算 /。对于除零操作,程序会返回一个特殊值 float('inf') 以表示错误。

4.生成子运算式

  • generate_subexpression(range_limit): 根据传入的数值范围,生成一个包含1到3个数的运算子表达式,可能包含分数和自然数。为了保证表达式不会生成负数,程序会在必要时将减法运算替换为加法运算,或重新生成运算数。

5.生成完整的表达式

  • generate_expression(range_limit): 这个函数生成一个由两个子运算式组成的完整四则运算表达式。程序确保运算表达式不会出现负数,并且在除法时避免除零操作。

6.生成题目和答案

  • generate_quiz(num_questions, range_limit): 根据传入的题目数量和数值范围,生成题目和答案。题目会被写入到 Exercises.txt 文件,答案会被保存到 Answers.txt 文件中。

7.批改答案

  • grade(exercise_file, answer_file): 读取题目和答案文件,逐一计算题目中的表达式并与答案文件中的答案进行对比。结果会分为正确和错误两个列表,并输出到 Grade.txt 文件中。

二、主函数模块

主函数使用 argparse 模块解析命令行参数。它支持以下几种命令:

  • -n 和 -r: 用于生成题目,-n 指定题目数量,-r 指定题目中数值的范围。例如:-n 10 -r 100 表示生成 10 道题目,数值范围在 0 到 100 之间。
  • -e 和 -a: 用于批改题目,-e 指定题目文件,-a 指定答案文件。
    根据传入的参数,程序会调用 generate_quiz 或 grade 函数来完成相应的任务。

三、设计优点

1.精确处理分数:通过 fractions.Fraction 确保分数运算准确,避免浮点误差,支持带分数格式转换。
2.题目生成灵活:随机生成自然数和分数,支持四则运算,避免负数和除零问题。
3.用户友好:命令行参数便于使用,生成题目和答案分别保存到文件,批改结果清晰呈现。
4.自动批改功能:精确对比答案与计算结果,正确和错误题目分开记录。
5.模块化设计:各功能独立,易于维护和扩展,支持性能分析。
6.智能表达式处理:通过正则表达式处理输入的带分数和分数形式,增加灵活性。

四、主要函数设计代码

1.带分数处理

# 将带分数的字符串转换为 Fraction
def mixed_to_fraction(mixed_str):if "'" in mixed_str:whole, frac = mixed_str.split("'")whole = int(whole)numerator, denominator = map(int, frac.split('/'))return fractions.Fraction(whole * denominator + numerator, denominator)elif "/" in mixed_str:numerator, denominator = map(int, mixed_str.split('/'))return fractions.Fraction(numerator, denominator)else:return fractions.Fraction(int(mixed_str), 1)# 将分数转换为带分数的字符串
def fraction_to_mixed(f):if f.denominator == 1:return str(f.numerator)elif f.numerator > f.denominator:whole = f.numerator // f.denominatorremainder = f.numerator % f.denominatorreturn f"{whole}'{remainder}/{f.denominator}" if remainder != 0 else str(whole)return str(f)

2.表达式的生成和计算

def eval_expression(expr):# 替换带分数为正确的 Fraction 表示expr = re.sub(r"(\d+)'(\d+)/(\d+)", lambda m: str(mixed_to_fraction(m.group(0))), expr)# 将分数转换为 Fraction 对象expr = re.sub(r"(\d+)/(\d+)", lambda m: str(fractions.Fraction(int(m.group(1)), int(m.group(2)))), expr)# 将 ÷ 替换为 /,使用 Fraction 处理除法expr = expr.replace('÷', '/')try:# 使用 eval 计算表达式,确保使用 fractions.Fraction 进行计算,避免浮点精度问题return eval(expr, {"__builtins__": None}, {"Fraction": fractions.Fraction})except ZeroDivisionError:return float('inf')  # 返回一个特殊值,表示出现了除以0的情况# 生成子运算式,包含 1 到 3 个运算数,避免负数,考虑优先级
def generate_subexpression(range_limit):num_count = random.randint(1, 3)  # 随机生成1到3个运算数numbers = [generate_number(range_limit) for _ in range(num_count)]operators = ['+', '-', '*', '÷']# 当产生的单运算数是分数时,加上括号,避免出错if num_count == 1:if numbers[0].denominator == 1:return fraction_to_mixed(numbers[0])  # 如果只有一个运算数,不需要括号else:return f"({fraction_to_mixed(numbers[0])})"subexpression = fraction_to_mixed(numbers[0])for i in range(1, num_count):op = random.choice(operators)# 避免除0if op == '÷' and numbers[i] == 0:numbers[i] = generate_number(range_limit)# 避免出现负数,出现时转换为加法if op == '-' and numbers[i] > numbers[i - 1]:op = '+'subexpression += f" {op} {fraction_to_mixed(numbers[i])}"if eval_expression(subexpression) < 0:subexpression = subexpression.replace('-', '+')# 如果有多个运算数,加上括号return f"({subexpression})" if num_count > 1 else subexpression# 生成完整的运算表达式,由 2 个子运算式组成,确保不会产生负数
def generate_expression(range_limit):subexpression_count = 2subexpressions = [generate_subexpression(range_limit) for _ in range(subexpression_count)]operators = ['+', '-', '*', '÷']# 避免最终表达式出现四个运算符matches = []for ch in subexpressions:if ch in operators:matches = matches.append(ch)expression = subexpressions[0]current_value = eval_expression(subexpressions[0])  # 计算当前表达式的值for i in range(1, subexpression_count):op = random.choice(operators)# 记录while len(matches) > 2 & (op not in matches):op = random.choice(operators)if op not in matches:matches.append(op)next_value = eval_expression(subexpressions[i])# 确保不会产生负数,出现时转换为加法if op == '-':if current_value - next_value < 0:op = '+'current_value = current_value + next_valueelse:current_value = current_value - next_value# 其他操作更新当前值elif op == '+':current_value = current_value + next_valueelif op == '*':current_value = current_value * next_valueelif op == '÷':while next_value == 0:subexpressions[i] = generate_subexpression(range_limit)  # 确保不除以0next_value = eval_expression(subexpressions[i])current_value = current_value / next_value# 拼接表达式expression += f" {op} {subexpressions[i]}"return expression, current_value

3.生成题目和答案

# 生成题目和答案
def generate_quiz(num_questions, range_limit):exercises = []answers = []for _ in range(num_questions):expression, answer = generate_expression(range_limit)while answer < 0:expression, answer = generate_expression(range_limit)exercises.append(expression)answers.append(fraction_to_mixed(fractions.Fraction(answer).limit_denominator()))with open("Exercises.txt", "w") as ex_file, open("Answers.txt", "w") as ans_file:for i, (exercise, answer) in enumerate(zip(exercises, answers), 1):ex_file.write(f"{i}. {exercise} = \n")

4.批改答案

# 批改答案
def grade(exercise_file, answer_file):with open(exercise_file, "r") as ex_file, open(answer_file, "r") as ans_file:exercises = ex_file.readlines()answers = ans_file.readlines()correct = []wrong = []for i, (exercise, answer) in enumerate(zip(exercises, answers), 1):# 去除题目中的编号,获取表达式部分expr = exercise.split('=')[0].strip()  # 去除 = 号后面的内容expr = re.sub(r'^\d+\.\s*', '', expr)  # 去除题目编号 "1. " 等格式# 将预期答案转换为标准 Fraction 形式expected_answer = answer.split('.')[1].strip()expected_fraction = mixed_to_fraction(expected_answer)# 计算表达式的答案calculated_fraction = fractions.Fraction(eval_expression(expr.replace('÷', '/'))).limit_denominator()# 比较计算结果和预期答案,统一比较 Fraction 对象而不是字符串if expected_fraction == calculated_fraction:correct.append(i)else:wrong.append(i)with open("Grade.txt", "w") as grade_file:grade_file.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")grade_file.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")

四、性能分析

通过cprofile可以对整个程序的执行进行性能分析,找到耗时较多的部分,然后进一步优化。
main函数运行

cProfile.run("main(orig_path, plagiarized_path, output_path)", filename="performance_analysis_result")

命令行运行

snakeviz.exe -p 8080 .\performance_analysis_result

得到性能分析图
1.题目生成

可见在批改函数中generate_expression运行时间最长,故可以考虑对函数generate_expression进行优化。

2.题目批改

可见在批改函数中eval_expression运行时间最长,故可以考虑对函数eval_expression进行优化。

五、单元测试

一、关于测试点的思维导图

二、主要测试代码

测试代码如下:
1.转换模块测试

# 测试混合分数转换def test_mixed_to_fraction(self):self.assertEqual(mixed_to_fraction("2'3/4"), fractions.Fraction(11, 4))self.assertEqual(mixed_to_fraction("3/5"), fractions.Fraction(3, 5))self.assertEqual(mixed_to_fraction("5"), fractions.Fraction(5, 1))# 测试分数转换为混合分数字符串def test_fraction_to_mixed(self):self.assertEqual(fraction_to_mixed(fractions.Fraction(11, 4)), "2'3/4")self.assertEqual(fraction_to_mixed(fractions.Fraction(3, 5)), "3/5")self.assertEqual(fraction_to_mixed(fractions.Fraction(5, 1)), "5")

2.表达式生成模块测试

# 测试减法不出现负数def test_no_negative_subtraction(self):for _ in range(100):  # 多次测试result = generate_subexpression(10)if '-' in result:# 检查是否产生负数eval_result = eval_expression(result.replace('÷', '/'))self.assertTrue(eval_result >= 0, "表达式不应生成负数")# 测试避免除以0def test_avoid_zero_division(self):for _ in range(100):  # 多次测试result = generate_subexpression(10)self.assertNotIn("0", result)  # 确保没有0作为除数
# 测试生成完整运算表达式def test_generate_expression(self):expression, answer = generate_expression(10)self.assertTrue(isinstance(expression, str))self.assertTrue(eval_expression(expression) >= 0)

3.计算模块测试

# 测试表达式求值def test_eval_expression(self):self.assertEqual(fractions.Fraction(eval_expression("(2'1/3 + 3/4)")).limit_denominator(),fractions.Fraction(37, 12))

4.文件处理模块测试

# 测试生成题目到文件def test_generate_quiz(self):generate_quiz(5, 10)with open("Exercises.txt", "r") as ex_file:exercises = ex_file.readlines()with open("Answers.txt", "r") as ans_file:answers = ans_file.readlines()self.assertEqual(len(exercises), 5)self.assertEqual(len(answers), 5)# 测试批改功能def test_grade(self):generate_quiz(5, 10)generate_quiz(5, 10)  # 生成一套题目以进行批改grade("Exercises.txt", "Answers.txt")with open("Grade.txt", "r") as grade_file:results = grade_file.read()self.assertIn("Correct:", results)self.assertIn("Wrong:", results)

5.参数处理模块测试

# 测试命令行参数处理错误情况def test_main_args_error(self):# 使用 mock 来测试错误情况with self.assertRaises(SystemExit):sys.argv = ["script_name"]main()

6.边界条件测试

 def test_generate_number_boundary(self):for _ in range(100):num = generate_number(1000)self.assertNotEqual(num.denominator, 0)

三、测试代码覆盖率

四、测试结果

六、项目总结

一、项目分工

郑玮源:负责大部分主函数代码和测试的编写
何昌洲:负责小部分代码补充和博客的编写

二、项目启发

在参与编程结对项目的过程中,我从技术层面和团队合作层面都获得了许多宝贵的经验与启发:
1.技术层面

  • 代码质量提升:结对编程的核心理念是两名开发者共同编写代码,一名编写代码,另一名审阅和提出建议。这种模式让我在编码时更加注重代码的清晰度、简洁性和可读性。通过互相审查代码,能够及时发现并修复潜在的代码问题,减少了低级错误的出现。
  • 最佳实践的学习:通过与结对伙伴的合作,我能够学习到他们的编程风格、常用的设计模式和工具链。这些在实际项目中可以快速应用,扩展了我的技术视野,帮助我在面对不同问题时有了更多的解决思路。
  • 快速调试与问题解决:与搭档一起调试程序时,我们能够在不同的思路下更快定位和解决问题。许多原本单人编程时会忽略的细节,通过结对时的讨论得以被及时发现,极大提高了调试效率。
  • 代码重构与优化:通过持续的代码审查和讨论,我们不仅能完成项目功能,还能对代码进行优化和重构,使其更具可维护性和扩展性。每当遇到复杂的逻辑,我们会互相探讨最优的设计方案,并进行合理的拆分和简化。
  • 工具链和开发流程:在项目中,我熟悉了版本控制工具Git和协作平台Github的使用,尤其是在代码合并、冲突解决和持续集成方面。结对项目的协作流程让我对这些工具的功能和用法有了更深入的理解。

2.团队合作层面

  • 沟通与反馈的有效性:结对编程需要双方在编码过程中持续保持沟通,及时给予反馈。通过这一过程,我学会了如何有效传达我的想法,并在听取他人建议时能够快速理解并回应。这种高效的沟通模式不仅在编程中受益,也为我今后在团队中的协作提供了很好的范例。
  • 责任感与共同目标:结对编程让我更深刻地体会到团队合作中的责任感。当我们一起面对项目中的难题时,我不再是单独为自己负责,而是为整个团队的目标负责。这种责任感促使我在项目的每个阶段都保持高效和专注,推动项目顺利进行。
  • 共享知识与经验:在合作的过程中,我们不仅是在完成项目,还在共享彼此的知识和经验。通过共同讨论和解决问题,我能够吸收到更多有用的经验和知识,同时我也乐于分享我所掌握的技术,这种双向的学习模式极大提升了团队的整体技术水平。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/65801.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第三天 | 熟悉链表

链表的存储方式数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。 链表是通过指针域的指针链接在内存中各个节点。 所以链表中的节点在内存中不是连续分布的 ,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。链表的定义 template <typ…

智慧工地火焰烟火识别检测系统

智慧工地火焰烟火识别检测系统通过深度学习技术,智慧工地火焰烟火识别检测系统对工地工厂区域自动发现浓烟和烟火迹象,立即抓拍告警并进行存档同步违规异常烟火信息回传给后台平台提醒后台人员及时处理。智慧工地火焰烟火识别检测系统可以减少因人工因素造成的乱报和瞒报现象…

车辆逆行识别预警系统

车辆逆行识别预警系统通过Python计算机算法技术,车辆逆行识别预警系统可以7*24小时不间断自动检测监控中道路来往行驶车辆出现逆行行为及时预警存档,同步将车辆违规行为信息回传给后台监控分析平台提醒值班人员及时处理预警。车辆逆行识别预警系统通过Opencv网络模型AI技术有…

信息学奥赛复赛复习06-CSP-J2020-02直播获奖-向上取整、向下取整、整数除法、最大值、最小值、计数排序

PDF文档公众号回复关键字:202409281 2020 CSP-J 题目1 优秀的拆分 [题目描述] NOI2130 即将举行。为了增加观赏性,CCF 决定逐一评出每个选手的成绩,并直播即时的获奖分数线。本次竞赛的获奖率为 w%,即当前排名前 w% 的选手的最低成绩就是即时的分数线 更具体地,若当前已评出…

渣土车智能识别系统

渣土车智能识别系统通过深度学习算法,渣土车智能识别系统对禁止渣土车通行现场画面中含有渣土车时进行自动识别监测,渣土车智能识别系统监测到监控画面中出现渣土车时,立即抓拍告警并同步提醒后台人员及时制止。渣土车智能识别系统促进后台日常“技防”智能化监管替代“人防…

[计算机网络]HTTP请求

HTTP 协议,建立在 TCP 连接基础之上的。HTTP 是一种允许浏览器向服务器获取资源的协议,是 Web 的基础,通常由浏览器发起请求,用来获取不同类型的文件,例如 HTML 文件、CSS 文件、JavaScript 文件、图片、视频等。此外,HTTP 也是浏览器使用最广的协议。 HTTP请求发起流程 …

软件工程结对项目

结对项目这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/homework/13230这个作业的目标 结对完成四则运算生成器项目成员伍绍雄 学号 3122004753 陈鸿航 学号 3122004732Github…

河道治理漂浮物识别监测系统

河道治理漂浮物识别监测系统通过深度视觉分析技术,河道治理漂浮物识别监测系统实时检测着河道水面是否存在漂浮物、水浮莲以及生活垃圾等。河道治理漂浮物识别监测系统识别到河道水面存在水藻垃圾等漂浮物,系统立即抓拍存档并同步发出报警。河道治理漂浮物识别监测系统可以提…