软工作业3:结对项目——实现一个自动生成小学四则运算题目的命令行程序

news/2024/9/19 17:59:54/文章来源:https://www.cnblogs.com/Onlyanose/p/18421014
这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/CSGrade22-34/
这个作业要求在哪里 结对项目 - 作业 - 计科22级34班 - 班级博客 - 博客园 (cnblogs.com)
这个作业的目标 结对项目——实现一个自动生成小学四则运算题目的命令行程序
成员1 陈奕奕 3222004552
成员2 林闰埼 3222004595

Only-a-nose/PairWork (github.com)

1. PSP2.1表格

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

2.性能分析

使用 cProfile 进行性能分析

cProfile 是 Python 内置的性能分析器,能够记录函数的调用次数和执行时间,帮助发现性能瓶颈。

  • 使用 cProfile 分析整个程序

在命令行运行程序时,使用 cProfile 来分析程序的性能,命令如下:

python -m cProfile -s time D:\pythonProject1\Software_Engineer\MyApp.py -n 10 -r 10
  • -s time:按执行时间对结果进行排序,找到执行时间最长的函数。

  • MyApp.py 后跟的参数依然是程序的命令行参数,比如 -n 是生成题目个数,-r 是数值范围。

  • 分析结果

cProfile 的输出将显示每个函数的以下内容:

  • ncalls:调用的次数。
  • tottime:该函数中不包括子函数的总执行时间。
  • percall:每次调用该函数的平均时间(tottime 除以 ncalls)。
  • cumtime:该函数及其子函数的累计执行时间。
  • percall (cumtime):每次调用该函数的累计时间(cumtime 除以 ncalls)。

  • 将性能分析结果保存为文件

可以将 cProfile 的结果输出到文件进行进一步分析:

python -m cProfile -o output.pstats D:\pythonProject1\Software_Engineer\MyApp.py -n 10 -r 10
  • 使用 pstats 模块对文件中的数据进行查看和排序
import pstats
p = pstats.Stats('C:\\Users\\陈奕奕\\output.pstats')
p.strip_dirs().sort_stats('time').print_stats(10)  # 打印执行时间最长的前10个函数

3.设计实现过程

1. 程序概述

本程序旨在生成小学四则运算题目,并且支持对用户的答案文件进行批改。程序通过命令行参数控制生成题目的数量、数值范围,以及判定答案的功能。生成的题目和答案分别存储在 Exercises.txtAnswers.txt 文件中,判定结果保存在 Grade.txt 文件中。

2. 代码组织结构

程序主要由四个功能模块组成:

  1. 生成题目:生成符合条件的四则运算表达式。
  2. 计算答案:计算生成题目的答案。
  3. 判定对错:根据用户提供的答案文件与程序计算的答案进行比较,输出批改结果。
  4. 命令行参数解析:解析用户通过命令行输入的参数,调用不同的功能。

3. 关键函数设计

  1. generate_question(range_value, operator_count=3)

    • 功能:根据给定数值范围 range_value 生成四则运算题目。
    • 输入:数值范围 range_value 和运算符个数 operator_count
    • 输出:返回一个运算表达式,包含自然数或真分数,以及最多 3 个运算符。
    • 逻辑:
      1. 随机生成自然数或真分数作为操作数。
      2. 随机选择运算符。
      3. 拼接操作数和运算符,生成一个完整的四则运算表达式。
  2. calculate_answer(expression)

    • 功能:根据生成的表达式计算答案。
    • 输入:四则运算表达式 expression
    • 输出:返回计算结果的真分数格式,或者在除零时返回 "undefined"。
    • 逻辑:
      1. 使用 Python 的 eval() 计算表达式。
      2. 捕捉除零异常,并输出 "undefined"。
  3. check_answers(exercise_file, answer_file)

    • 功能:检查用户提供的答案文件,判定每道题目对错。
    • 输入:题目文件路径 exercise_file 和答案文件路径 answer_file
    • 输出:生成一个包含判定结果的 Grade.txt 文件。
    • 逻辑:
      1. 读取题目和答案文件,按行处理。
      2. 逐行比较程序计算的答案和用户提供的答案,统计正确与错误的题目。
      3. 将结果写入 Grade.txt
  4. generate_exercises_and_answers(n, range_value)

    • 功能:生成 n 道题目并计算答案,存入 Exercises.txtAnswers.txt 文件。
    • 输入:题目个数 n 和数值范围 range_value
    • 输出:生成的题目和答案分别存入两个文件中。
  5. main()

    • 功能:命令行解析,控制程序的整体逻辑。
    • 逻辑:
      1. 如果传入 -n-r 参数,生成指定数量的题目和答案。
      2. 如果传入 -e-a 参数,进行答案对错判定。
      3. 如果参数不全,打印帮助信息。

4. 模块之间的关系

  • 生成题目模块generate_question())会调用生成随机数和运算符,最终返回一个四则运算表达式。
  • 计算答案模块calculate_answer())会对生成的四则运算表达式进行计算,并将结果以真分数的形式返回。
  • 判定对错模块check_answers())读取生成的题目和用户提供的答案进行比较,统计对错并输出到文件。
  • 命令行解析模块main())控制程序的主流程,解析参数决定调用生成题目或判定答案的功能。

5. 关键流程图

1. generate_question() 函数流程图

2. calculate_answer() 函数流程图

3. check_answers() 函数流程图

6. 总结与改进

  • 该程序的设计简洁,使用了模块化设计,方便各个功能的扩展。
  • 使用命令行参数控制生成题目和判定答案功能,使得程序灵活性较强。
  • 在未来的改进中,可以增加更多的输入校验功能,如防止用户输入无效参数,或者确保用户提供的答案文件格式正确。

4.代码说明

1. 模块导入

import argparse
import random
from fractions import Fraction
  • argparse:用于处理命令行参数。
  • random:用于生成随机数,帮助创建随机四则运算题目。
  • fractions.Fraction:用于处理真分数,使得生成题目时可以包含分数运算。

2. 生成四则运算题目的函数:generate_question()

def generate_question(range_value, operator_count=3):operators = ['+', '-', '*', '/']numbers = []for _ in range(operator_count + 1):if random.choice([True, False]):numerator = random.randint(1, range_value - 1)denominator = random.randint(2, range_value)fraction = Fraction(numerator, denominator)numbers.append(fraction)else:numbers.append(random.randint(1, range_value - 1))expression = str(numbers[0])for i in range(operator_count):op = random.choice(operators)expression += f" {op} {numbers[i + 1]}"return expression
  • 功能:随机生成包含真分数和自然数的四则运算题目。
  • 参数
    • range_value:控制生成的随机数的范围。
    • operator_count:控制运算符的数量,默认是3个运算符。
  • 流程
    1. 随机选择数字,可以是自然数或真分数。
    2. 在数字之间插入随机运算符(+, -, *, /)。
    3. 返回完整的四则运算表达式字符串。

3. 计算表达式结果的函数:calculate_answer()

def calculate_answer(expression):try:answer = eval(expression)return str(Fraction(answer).limit_denominator())except ZeroDivisionError:return "undefined"except Exception as e:return f"Error: {e}"
  • 功能:计算四则运算题目的正确答案。
  • 参数expression 是待计算的数学表达式字符串。
  • 流程
    1. 使用 Python 的内置 eval() 函数计算表达式的值。
    2. 将计算结果转换为最简分数形式。
    3. 如果遇到除以零错误,返回 "undefined"
    4. 处理其他异常并返回错误信息。

4. 判定答案对错的函数:check_answers()

def check_answers(exercise_file, answer_file):with open(exercise_file, "r") as ef, open(answer_file, "r") as af, open("Grade.txt", "w") as grade_file:correct = []wrong = []exercises = ef.readlines()answers = af.readlines()for i in range(len(exercises)):exercise = exercises[i].split('=')[0].split('. ')[1].strip()expected_answer = calculate_answer(exercise)given_answer = answers[i].split(". ")[1].strip()if expected_answer == given_answer:correct.append(i + 1)else:wrong.append(i + 1)grade_file.write(f"Correct: {len(correct)} ({', '.join(map(str, correct))})\n")grade_file.write(f"Wrong: {len(wrong)} ({', '.join(map(str, wrong))})\n")
  • 功能:检查学生的答案是否正确,并将结果写入 Grade.txt 文件。
  • 参数
    • exercise_file:题目文件的路径。
    • answer_file:答案文件的路径。
  • 流程
    1. 从题目文件和答案文件中读取数据。
    2. 对每个题目,提取出数学表达式并计算正确答案。
    3. 比较计算的答案和给出的答案。
    4. 记录正确和错误的题目编号,并将结果写入 Grade.txt 文件。

5. 生成题目和答案的函数:generate_exercises_and_answers()

def generate_exercises_and_answers(n, range_value):with open("Exercises.txt", "w") as exercise_file, open("Answers.txt", "w") as answer_file:for i in range(1, n + 1):question = generate_question(range_value)answer = calculate_answer(question)exercise_file.write(f"{i}. {question} =\n")answer_file.write(f"{i}. {answer}\n")
  • 功能:生成题目和对应的答案,分别写入 Exercises.txtAnswers.txt 文件中。
  • 参数
    • n:题目的数量。
    • range_value:控制生成的随机数的范围。
  • 流程
    1. 生成指定数量的四则运算题目。
    2. 计算每道题目的正确答案。
    3. 将题目和答案分别写入两个文件中。

6. 主函数:main()

def main():parser = argparse.ArgumentParser(description="四则运算生成器")parser.add_argument("-n", type=int, help="生成题目的个数")parser.add_argument("-r", type=int, help="题目中数值的范围")parser.add_argument("-e", type=str, help="题目文件路径")parser.add_argument("-a", type=str, help="答案文件路径")args = parser.parse_args()if args.n is not None and args.r is not None:generate_exercises_and_answers(args.n, args.r)print(f"生成了 {args.n} 道题目,数值范围为 0 到 {args.r}")elif args.e and args.a:check_answers(args.e, args.a)print(f"判定答案对错,结果已存入 Grade.txt 文件。")else:parser.print_help()
  • 功能:处理命令行参数,调用相应的功能。
  • 参数说明
    • -n:生成题目的数量。
    • -r:控制生成题目的数值范围。
    • -e-a:分别指定题目文件和答案文件的路径,用于判定答案对错。
  • 流程
    1. 如果提供了 -n-r 参数,生成题目和答案文件。
    2. 如果提供了 -e-a 参数,检查给出的答案是否正确。
    3. 如果参数不完整,显示帮助信息。

7. 程序入口

if __name__ == "__main__":main()
  • 功能:这是标准的 Python 程序入口,确保当文件作为脚本运行时调用 main() 函数。

5.测试运行

  1. 生成10道题目,数值范围在10以内

    python MyApp.py -n 10 -r 10
    
  2. 检查题目和答案文件的对错

    python MyApp.py -e Exercises.txt -a Answers.txt
    
  3. 命令窗口:


  1. 运行结果:

    • Exercises.txt

  • Answers.txt

  • Grade.txt

6.项目小结

1. 项目背景与目标

在这个结对项目中,我们的目标是开发一个四则运算题目生成器,并实现一个自动化的答案判定系统。该系统需要支持生成随机的四则运算题目(包括自然数和真分数),计算这些题目的正确答案,并对给出的答案进行准确的判定。项目的关键任务包括编写代码来生成题目、计算答案、检查答案的正确性,以及处理命令行参数以实现这些功能。

2. 成功经验

1. 任务分配与协作

我们在项目初期对任务进行了合理的分配。一方负责设计和实现题目生成和答案计算的核心逻辑,另一方则专注于答案的判定和命令行接口的实现。这种分工有效提高了工作效率,使得每个人可以专注于自己擅长的领域。

2. 测试与调试

我们制定了详尽的测试计划,包括单元测试和集成测试。通过 PyCharm 和命令行进行性能分析和测试,及时发现了潜在的问题并进行了修复。这种方法确保了代码的稳定性和准确性。

3. 文档与说明

我们在代码中添加了详细的注释和文档说明,解释了每个函数的功能和参数。这不仅帮助我们自己在后续维护时更容易理解代码,也使得项目对其他开发者更友好。

3. 遇到的挑战与教训

1. 异常处理

在处理四则运算题目的计算时,我们遇到了除以零的错误。最初没有考虑到这一点,导致了程序崩溃。经过调整,我们加入了专门的异常处理机制,以确保程序在遇到除以零的情况时能够返回 "undefined",而不是崩溃。

2. 参数处理

最开始对命令行参数的处理不够完善,导致在不同环境下运行时出现了参数解析错误。通过调试和修正,我们改善了参数处理的代码,确保了命令行工具的稳定性和可靠性。

3. 文件路径问题

在读取文件路径时,遇到了 Unicode 编码问题。通过使用原始字符串(r'path')来处理路径,我们解决了这个问题,并确保代码在不同操作系统上能够正常运行。

4. 结对感受

合作中的闪光点
  • 高效的沟通:我们在项目中保持了频繁而有效的沟通。每当遇到问题时,我们都能够迅速协作找到解决方案。这种高效的沟通大大提高了项目的推进速度。
  • 互补的技能:我们两个人在技能上互补,一方擅长逻辑和算法设计,另一方则精通命令行工具和文件操作。这种互补让我们的项目在各方面都能达到较高的质量。
建议
  • 定期代码审查:虽然我们在项目中保持了良好的沟通,但定期的代码审查可以帮助更早地发现潜在问题。建议在未来的项目中加入更多的代码审查环节。
  • 增强文档编写:虽然项目中有详细的注释和文档,但在复杂的功能实现中,提供更多的技术文档和使用指南会更有助于项目的维护和扩展。

5. 总结

通过这次结对项目,我们不仅完成了四则运算题目生成器和答案判定系统的开发任务,还在实践中积累了宝贵的经验。项目中的挑战和问题让我们认识到在开发过程中异常处理和参数管理的重要性,同时也让我们意识到团队合作和技能互补的优势。未来,我们将继续优化我们的工作方法,以确保项目的高效和稳定运行。


博文撰写者: 陈奕奕 和 林闰埼

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于LangChain手工测试用例转App自动化测试生成工具

在传统编写 App 自动化测试用例的过程中,基本都是需要测试工程师,根据功能测试用例转换为自动化测试的用例。市面上自动生成 Web 或 App 自动化测试用例的产品无非也都是通过录制的方式,获取操作人的行为操作,从而记录测试用例。整个过程类似于但是通常录制出来的用例可用性…

单细胞数据 存储方式汇总

(单细胞下游分析——不同类型的数据读入,与部分数据类型的转化) .h5ad(anndata 数据格式) 10x_mtx(cell ranger输出,三个文件) 就是cell ranger上游比对分析产生的3个文件: ├── xxx_feature_bc_matrix │ ├── barcodes.tsv.gz:细胞标签(barcode) │ ├──…

springcloud组件openfeign超时时间设置

openfeign超时时间设置有两种方式 1、通过配置类;2、通过配置文件 1、使用配置类代码如下:@Configuration public class FeignConfig {@Beanpublic Request.Options options(){//第一个参数是连接超时时间,第二个参数是处理超时时间return new Request.Options(5000,3000);}…

python虚拟环境venv

创建目录 mkdir pyenv 进入 cd pyenv 初始化环境 python3 -m venv .进入bin目录 jihan@jihandeMacBook-Pro pyenv % cd bin jihan@jihandeMacBook-Pro bin % ls Activate.ps1 activate activate.csh activate.fish pip pip3 pip3.12 python python3 python3.12 jihan@jiha…

进行网站监控有必要吗?

在当今数字化高速发展的时代,网站已经成为了企业、组织乃至个人展示自身形象、提供服务、进行交流互动的重要平台。那么,进行网站监控有必要吗?答案无疑是肯定的。 进行网站监控,首先是保障用户体验的关键。对于访问网站的用户来说,他们期望能够快速、稳定地获取所需信息或…

Typora+picgo+jsDelivr实现免费图床

Typora+picgo+github+jsDelivr实现免费图床 需求 typora中写markdown图片是保存在本地的,为了简化写博客时繁琐的插入图片步骤,直接使用typora+picgo将图片上传到云端,这样发博客就只要复制markdown即可 步骤 前期准备:github中创建一个仓库用于保存图片 名字随便填就行1.下…

线上间歇性卡顿问题

事情起因 最近一段时间我们公司有个项目是做视力筛查的,平时都是正常的,但是最近这两天突然会时不时地卡顿一下,一卡就是几分钟。排查过程 1.查看日志 卡顿首先是排查日志,日志报的是feign调用学生服务超时,进到学生服务查看时,看到日志报的是事务超时2.继续排查,既然是…

关于springcloud中openfeign中服务调用日志输出

在使用openfeign进行服务调用的时候,我们可以通过一些配置,获取到服务调用的日志输出,可以从消费端看到日志 有两种方法:一、使用配置类;二、使用配置文件配置 日志输出级别有四种: NONE:不输出(默认) BASIC:只输出请求方式、url、请求成功与否 HEADERS:输出请求头的…

《现代操作系统》第10章——实例研究1:UNIX、Linux和Android

《现代操作系统》第 10 章——实例研究 1:UNIX、Linux 和 Android 10.1 UNIX 与 Linux 的历史 第一次使 UNIX 的两种流派一致的严肃尝试来源于 IEEE(它是一个得到高度尊重的中立组织)标准委员会的赞助。有上百名来自业界、学界以及政府的人员参加了此项工作。他们共同决定将…

linux使用yum命令报错Cannot find a valid baseurl for repo: base/7/x86_64

【问题】 在VMware上安装搭建centOS 7虚拟机,配置好网络后,尝试通过yum命令进行安装docker容器。执行命令报错: 已加载插件:fastestmirror, langpacks Loading mirror speeds from cached hostfile  Could not retrieve mirrorlist http://mirrorlist.centos.org/?relea…

研发工程师的「第一性原理」思维

回顾复盘五年来的研发经历,愈发认同身边同事强调的“第一性原理”思维,仅做浅浅记录和分享一、定义与理论介绍第一性原理(First Principles),又称基本原理,是指从最基本的假设和定义出发,通过逻辑推理和演绎得出结论的一种思维方法。它强调对事物的本质和根源进行深入的…

Meta Llama3 论文研读

一、 引言概述(Intro & Overview) Llama3是一系列基于Transformer结构的大型多语言模型,通过优化数据质量、训练规模和模型架构,旨在提升模型在各种语言理解任务中的表现。通过引入更优质的数据和更高效的训练方法,Llama3展示了在自然语言处理领域的巨大潜力。其创新点…