• 软件工程实践寒假作业(2/2)


    这个作业属于哪个课程 班级链接
    这个作业要求在哪里 作业链接
    这个作业的目标 完成项目
    作业正文 本页
    其他参考文献

    Github

    本项目使用Python3.7

    https://github.com/Mauue/InfectStatistic-main


    PSP表格

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

    解题思路

    由于需求文档足够清晰,看完之后我就把项目大致规划为三个部分

    1.解析命令行参数

    该项因为之前没写过,所以单独列出来。刚开始查阅资料后,找到了个看似可以的模块 getopt模块。但是仔细阅读需求文档发现,需求是解析list子命令,getopt好像不能解析子命令,查阅了官方文档也没看见。不过官方文档里给出了另一条路:

    The getopt module is a parser for command line options whose API is designed to be familiar to users of the C getopt() function. Users who are unfamiliar with the C getopt() function or who would like to write less code and get better help and error messages should consider using the argparse module instead.

    于是就采用了argparse模块
    之后对着文档操作了一波,能顺利执行下去,此部分暂告一段落。

    2.解析日志文件

    对txt日志文件进行解析

    该日志中出现以下几种情况:
    1、<省> 新增 感染患者 n人
    2、<省> 新增 疑似患者 n人
    3、<省1> 感染患者 流入 <省2> n人
    4、<省1> 疑似患者 流入 <省2> n人
    5、<省> 死亡 n人
    6、<省> 治愈 n人
    7、<省> 疑似患者 确诊感染 n人
    8、<省> 排除 疑似患者 n人

    看的这段话后第一反应就是用正则,想了想应该是可行的,此部分就先这样。

    3.计算并输出具体数据

    将上一部分的解析结果存储起来,按照要求输出出去,因为两个部分都不难,所以放在一起写。


    设计实现过程

    按照上一部分的内容,设计出以下逻辑图


    代码说明

    程序的关键是对日志进行处理。

    首先设计数据结构

        def _new_province(self, province):
            self.data.update({province: {"ip": 0, "sp": 0, "cure": 0, "dead": 0}})
    

    数据按照省份的四项数据进行存储

    之后是数据处理函数

        def _add_people(self, province, num, _type, _sub=False):
            num = -int(num) if _sub else int(num)
            if province not in self.data:
                self._new_province(province)
            self.data[province][_type] += num
    

    操作的最小步骤为某一省份的某一数据增加或减少一定数量,所以设计了以上函数来处理。

    解析日志的函数如下

        def _parse_line(self, line):
            if line.startswith('//'):
                return
            _patterns = [
                ('(.*?) 新增 感染患者 ([0-9]+)人', (((1, 2), 'ip', False),)),
                ('(.*?) 新增 疑似患者 ([0-9]+)人', (((1, 2), 'sp', False),)),
                ('(.*?) 感染患者 流入 (.*?) ([0-9]+)人', (((1, 3), 'ip', True), ((2, 3), 'ip', False))),
                ('(.*?) 疑似患者 流入 (.*?) ([0-9]+)人', (((1, 3), 'sp', True), ((2, 3), 'sp', False))),
                ('(.*?) 死亡 ([0-9]+)人', (((1, 2), 'dead', False), ((1, 2), 'ip', True))),
                ('(.*?) 治愈 ([0-9]+)人', (((1, 2), 'cure', False), ((1, 2), 'ip', True))),
                ('(.*?) 疑似患者 确诊感染 ([0-9]+)人', (((1, 2), 'sp', True), ((1, 2), 'ip', False))),
                ('(.*?) 排除 疑似患者 ([0-9]+)人', (((1, 2), 'sp', True),)),
            ]
            for _pattern, _args_list in _patterns:
                result = re.match(_pattern, line)
                if result:
                    for _args in _args_list:
                        index, _type, _sub = _args
                        province, num = result.group(*index)
                        self._add_people(province, num, _type, _sub)
                    return
    

    通过匹配正则表达式来解析日志的数据,若之后出现其他的日志格式也可以直接在这添加语句。

    拼音排序部分参考了这篇文章

    其他部分个人认为较为简单,不再说明。


    单元测试

    我设计了16种测试用例,覆盖了不同的参数出现可能和可能发生的错误。

    测试结果如下:


    覆盖率和性能测试

    • 覆盖率
      除主程序入口和解析参数外 其余代码全部覆盖。

    • 性能测试

      • 时间

        耗时最多的的函数是

        • <built-in method _locale.setlocale> 耗时最多的是locale模块的设置语言环境,用于拼音排序,只调用了一次。
        • <built-in method io.open> 打开文件
        • <built-in method nt.stat> 这个查阅资料后发现此函数是用于获取文件信息的,调取log文件时要根据文件名筛选正确格式的日志文件,所以这个函数的调用次数取决于log目录下的文件数 量。
      • 调用次数

        主程序运行部分集中在图的上半部分左侧,运行较多的主要是正则模块相关部分。


    代码规范

    链接


    心路历程与收获

    有一说一,这次的作业不难,甚至还没开始设计,我都想好了代码会长什么样,该怎么写。
    开发速度还是很快的,完成全部功能大概就两个小时,剩下的都是对需求细节的调整。

    收获主要是单元测试和性能分析。

    单元测试我以前也写过一点,但是写的不多,因为觉得太麻烦了。但是这次作业我认真的写了十几种测试用例后,尤其是对于接下来的性能分析,测试结果对我的代码帮助真的很大,以后可能会写的多一些。

    性能分析这一块,因为pycharm的单元测试机制和其他各种原因,这块的报告我写了四次,每次写到一半发现有些函数根本不知道是在哪调用的,然后发现都是各种原因引入了与主程序无关的函数,导致的错误。摸索挺久算是找到个合理的解决方案,也是不容易。


    5个仓库

      • 名称:Tinode Instant Messaging Server
      • github地址: https://github.com/Mauue/chat
      • 简介:即时消息服务器后端,由go开发,一个大型的开源项目,支持gRPC等技术,一个值得去学习的项目。
      • 名称:kratos
      • github地址: https://github.com/Mauue/kratos
      • 简介:bilibili开源的一套Go微服务框架,包含大量微服务相关框架及工具。
      • 名称:Archery
      • github地址: https://github.com/Mauue/Archery
      • 简介:Python项目,定位于SQL审核查询平台,旨在提升DBA的工作效率,支持主流数据库的SQL上线和查询,同时支持丰富的MySQL运维功能,所有功能都兼容手机端操作
      • 名称:git-webhook
      • github地址: https://github.com/Mauue/git-webhook
      • 简介:一个使用 Python Flask + SQLAchemy + Celery + Redis + React 开发的用于迅速搭建并使用 WebHook 进行自动化部署和运维系统。
  • 相关阅读:
    SmartTimer——一种基于STM32的轻量级时钟调度器
    Python2/3中的urllib库
    Python 解析构建数据大杂烩 -- csv、xml、json、excel
    Python2/3 中执行外部命令(Linux)和程序(exe) -- 子进程模块 subprocess
    Python 中的命令行参数处理 -- argparse、optparse、getopt
    Linux 定时循环执行 python 脚本
    Python2/3的中、英文字符编码与解码输出: UnicodeDecodeError: 'ascii' codec can't decode/encode
    在windows下使用Qt5开发GTK3图形界面应用程序
    qt编译的基于xlib cairo的桌面程序
    debian安装dwm窗口管理器
  • 原文地址:https://www.cnblogs.com/hcy-blog/p/12267022.html
Copyright © 2020-2023  润新知