• 项目——四则运算器


      Github:https://github.com/Hessess/SiZe

      首先,mark下阅读《构建之法》前三章喜欢的两句话:“我总觉得灵感是属于业余爱好者的。我们职业人工只是每天持续工作。今天你继续昨天的工作,明天你继续今天的工作,最终你会有所成就。”和“过早的优化是一切罪恶的根源。”

      不发表什么读后感,接下来进入正题——四则运算器

    题目:

      (1)能自动生成小学四则运算题目,并且不能出现负数;

      (2)能支持真分数的四则运算;

    思路:

      题目一看还挺简单,生成随机整数,然后进行四则运算,就是真分数这一点需要动点脑筋。然后就想做个界面出来,毕竟有个tkinter库,看了下书,嗯好像不难。脑子一闪又想把上学期实训时自学的一点Qt给用上,上网搜索“Qt python”,折腾折腾花去好多时间,什么都没做出来。还是先把四则运算做好吧。

      几个思路:

      (1)a-b,必须a>=b;

      (2)a÷b,避免出现a>b,并且a不能被b整除的情况,且b不为0;

      (3)题目要求的是支持真分数的四则运算,那么结果出现假分数是被允许的;

      (4)加载“tkinter”库,设计窗口来实现功能;

      (5)利用“random.randint(x,y)”函数来产生要运算整数,分数由两个随机整数生成,分母不为0;

      (6)加载“fractions”库,来实现分数的生成和四则运算;

      但是作业的要求不止于此,我觉得除编程外的的工作才是重点吧,像《构建之法》第二种讲的学习个人开发流程,代码测试,性能优化等。这些第一次接触,边走边看吧。

    实现过程:

      关键函数:

      def button(): #按钮处理函数
      def Newq():#整数的加减乘除 
      def newF():#分数的加减乘除

      实现过程:

      首次按下按钮开始做题,生成题目。再次按下按钮,获取用户输出内容,与正确答案匹配,生成“题目+答案+用户答案+正确与否”字符串,放置Listbox控件;当做到30的倍数时,弹窗提示做题数目和正确数目。

    代码说明:

      以下为关键的三个函数,思路和注释都在代码注明,这里不再赘述。

    def button(): #按钮处理函数
        #buttonNew.place_forget() #隐藏button
        global Number
        global RAns
        global Rnum
        if Number is 0: #开始步骤
            EnterAns.delete('0','end')
            listAns.insert(0, "开始答题~~")
            buttonNew["text"] = "下一题"
            R = Newq()  # 获取新问题
            Q1["text"] = R[1]  # 问题
            RAns=R[0]
            Number+=1
        else:  #先判断上一题是否正确再生成新题目 每5道有一道为真分数的运算
            User_A = EnterAns.get()
            u=Q1["text"]+"="+str(RAns)+"    your "+User_A+":"
            if User_A == str(RAns): #匹配答案
                u += " right"
                Rnum+=1
            else:
                u += " wrong"
            listAns.insert(0, u)
            if Number%5!=0:
                R = Newq()  # 获取整数新问题
            else:
                R=newF() # 获取分数新问题
            Q1["text"] = R[1]  # 问题
            RAns = R[0]  #正确答案
            Number += 1
            EnterAns.delete('0', 'end') #清空输入框
        if Number%30 == 0 :
            sss='你做了'+str(Number)+'道题,对了'+str(Rnum)+'道'
            tkinter.messagebox.showinfo("well done",sss)
    

      

    #整数的加减乘除
    def Newq():
        s=['+','-','×','÷']
        q=[]
        s_num=random.randint(0, 3)
        if s_num is 0 :#加法
            a=random.randint(0,50)
            b=random.randint(0,50)
            q.append(a+b)
            q.append(str(a)+' '+s[s_num]+' '+str(b))
            return q
        elif s_num is 1 :#减法
            a=random.randint(0,50)
            b=random.randint(0,a)
            q.append(a - b)
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
        elif s_num is 2 :#乘法
            a=random.randint(0,20)
            b=random.randint(0,20)
            q.append(a * b)
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
        else : #除法
            a=random.randint(0,20)
            b=random.randint(1,20)
            if (a>b and a%b!=0): #避免出现 20/3 这样的问题
                tmp=a
                a=b
                b=tmp
            c=Fraction(a,b)
            q.append(str(c))
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
    

      

    #分数的加减乘除  
    def newF():
        s=['+','-','×','÷']
        q=[]
        s_num=random.randint(0, 3)
        t1 = random.randint(0, 20)
        if t1==0:
            t2=random.randint(1, 20)
        else:
            t2 = random.randint(t1, 20)
        a=Fraction(t1,t2)
        t1 = random.randint(1, 20)
        if t1==0:
            t2=random.randint(1, 20)
        else:
            t2 = random.randint(t1, 20)
        b = Fraction(t1, t2)
        if s_num is 0 :#加法
            q.append(a+b)
            q.append(str(a)+' '+s[s_num]+' '+str(b))
            return q
        elif s_num is 1 :#减法
            if a<b:
                tm=a
                a=b
                b=tm
            q.append(a - b)
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
        elif s_num is 2 :#乘法
            q.append(a * b)
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
        else : #除法
            c=Fraction(a,b)
            q.append(str(c))
            q.append(str(a) + ' '+s[s_num]+' ' + str(b))
            return q
    

      

    测试运行:

    单元测试:

      测试newF()函数,生成1000个式子,出现报错,错误信息在“fractions.py”中,报错信息行如下:

      

      经过查找,发现错误代码如下:

    t1 = random.randint(0, 20)
    t2 = random.randint(t1, 20)
    a=Fraction(t1,t2)
    t1 = random.randint(0, 20)
    t2 = random.randint(t1, 20)
    b = Fraction(t1, t2)
    

      错误原因一为生成分数的时候,当t1为0时,t2可能也为0,即分母为0;二为生成b时,未考虑其作为除数的情况,即它不能为0;经过修改,这部分代码为:

        t1 = random.randint(0, 20)
        if t1==0:
            t2=random.randint(1, 20)
        else:
            t2 = random.randint(t1, 20)
        a=Fraction(t1,t2)
        t1 = random.randint(1, 20)
        if t1==0:
            t2=random.randint(1, 20)
        else:
            t2 = random.randint(t1, 20)
        b = Fraction(t1, t2)
    

      问题解决。

      测试Newq()函数,生成1000个式子,无问题,如下:

        

    全局测试:

          

      可以看到,没有负数出现,问题没有出现假分数,分数的四则运算和整数的除法结果也都是约分了而且正确的。

          

      再给个弹窗的效果图,为了不麻烦就不输答案直接点下一题下一题了,弹窗信息结果是30道对0道。

    性能分析优化:

      PyCharm提供了性能分析工具Run——Profile,如下图所示。利用Profile工具可以对代码进行性能分析。

        

      性能统计界面由Name、Call Count、Time(ms)、Own Time(ms) 4列组成一个表格,见下图。表头Name显示被调用的模块或者函数;Call Count显示被调用的次数;Time(ms)显示运行时间和时间百分比,时间单位为毫秒(ms)。

         

       可以看到大部分的时间是在等待用户输入,内置函数占用时间最大的是按钮的事件处理函数“button()”,也是整个项目的核心,而这些时间也是被生成弹窗给占用了。下图为运行不到30次没有弹窗生成的结果,在依时间来排列第一页甚至看不到“button()”。

    ·    

      再看其他俩个主要函数:

      

      生成整数题目调用了25次,生成分数题目调用了5次,占用时间都为0。

      很遗憾,能力有限也找不到可以进行优化的地方。

    PSP表格:

        预计耗时(分钟) 实际耗时(分钟)
    Planning 计划 3  3
    Estimate 估计这个任务需要多少时间 3  3
    Development 开发 76  130
    Analysis 需求分析  1  5
    Design Spec 生成设计文档  0
    Design Review 设计复审(和同事审核设计文档)  5  0
    Coding Standerd 代码规范(为目前的开发制定合适的规范)  0
    Design 具体设计 5  20
    Coding 具体编码 40 90
    Code Review 代码复审 5  10
    Text 测试(自测,修改代码,提交修改)  20  5
    Reporting 报告  12  22
    Text Report 测试报告 8  15
    Size Measurement 计算工作量  2  2
    Postmortem & Process Improvement Plan 事后总结,并提出过程改进计划 2  5
    Sum 合计 91  155

      比想象中的难得多,就这个分数的处理就想了挺久。设计文档和代码复审没做也不知道是什么,所以时间为0。至于测试,我是边写边测试边改,把所有时间放在了“具体编码”上,那测试的时间,就写最后一次测试,也就反复生成一千个式子来试试,最后发现个问题,然后修改的时间了。

      实际操作时间可能比表格写的久,因为花了一早上来完成代码写博客上传文件什么的,虽然中间有玩手机什么的。

      ---2018.4.17

  • 相关阅读:
    Redis使用初步
    Servlet Java Web开发(3.1) request response
    TcpClient例子(2)更robust的程序
    C#多线程之ManualResetEvent,Thread,ThreadPool,BackgroudWoker
    使用TcpClient的例程
    C#中多线程修改UI
    C# 多线程之异步回调
    Servlet Java Web开发(3) request response和编码
    Eclipse 和MyEclipse下Servlet Java Web开发(2)
    Eclipse 和MyEclipse下Servlet Java Web开发(1)
  • 原文地址:https://www.cnblogs.com/hesse/p/8859016.html
Copyright © 2020-2023  润新知