结对编程作业:小学四则运算

艾克达热夏提 2022-09-29 15:42:44
姓名学号
艾克达·热夏提3220005182
陈梓荣3220005183

0.作业声明

这个作业属于哪个课程广工软件工程学习社区
作业要求要求
作业目标目标

1.作业github链接

作业github链接/3220005182
作业github链接/3220005183

2.PSP表格

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

3.效能分析

1.性能分析工具(VS 2019)

img

img

2.程序中消耗最大的函数

此处从gen_work函数逐层分析寻找消耗最大函数,最终得出gen_work->gen->calculate_all->calculate

img

img

img

img

img

4.设计实现过程

1.程序简介

看一下题目说明,既然要生成多种数据,那么就要去写多种数据生成函数,整数、分数、带分数分别各一个生成函数,然后随机生成符号,再随机嵌入括号对,生成最终的表达式,这里注意要去重,避免生成重复的表达式,最终送入计算函数,做完实现的程序,就可以加上图形界面了,程序分为两个文件组成,一个是函数文件bitter_work.py,一个是图形化界面驱动文件window.py

2.程序流程图

img

5.代码说明

a.最大公因子计算函数gcd

使用辗转相除法,递归调用函数自身,求出传入的两个参数的最大公因子,提供给后面约分和通分调用

def gcd(a, b):  # 使用辗转相除法计算两个数的最大公因子
    
    if a % b == 0:
        return b
    else:
        return gcd(b, a % b)

b.约分函数reduce

将传入的分数分出分子与分母,调用gcd函数,得到分子和分母的最大公因子,分子分母同除公因子,得到约分结果,如果此时分母为1,则约分结果为整数

def reduce(string):  # 对一个分数进行约分

    a_b = string.split("/")
    a = int(a_b[0])
    b = int(a_b[1])
    max_factor = gcd(a, b)
    after_a = a // max_factor
    after_b = b // max_factor
    after_string = str(after_a) + "/" + str(after_b)
    if after_b == 1:
        after_string = str(after_a)
    return after_string

c.生成真分数函数gen_fraction

由于题目要求规定分母不能超过传入的最大值参数,所以这里生成分子和分母需要注意randint的范围,分母的范围是2到最大值减一,分子的范围是1到分母减一,得到一个分数,但此时不一定是真分数,所以需要调用约分函数,将分数转为真分数

def gen_fraction(max_num):  # 生成一个真分数

    mother = random.randint(2, max_num-1)
    son = random.randint(1, mother-1)
    after_string = str(son) + "/" + str(mother)
    fraction = reduce(after_string)
    return fraction

d.生成数字函数gen_number

首先判断一下传入最大值是什么,由于题目要求传入最大值为1程序仍可以运行,所以这里需要给予一个特殊情况,当传入最大值为1时,由于只能生成分数,为确保题目的数量充足,所以将分母的取值范围更换为2到100,生成之后同样经过一次约分

其次,对于其他最大值,则可以正常生成数字,使用一个randint(0, 2),如果是0,生成整数;如果是1,生成真分数;如果是2,生成带分数。由于题目规定整数同样不能超过最大值,所以整数的范围是1到最大值减一;对于带分数,其实就是一个整数接一个真分数,这里的整数范围依然是1到最大值减一

def gen_number(max_num):  # 生成数字

    if max_num == 1:
        mother = random.randint(2, 100)
        son = random.randint(1, mother - 1)
        after_string = str(son) + "/" + str(mother)
        number = reduce(after_string)
    else:
        flag = random.randint(0, 2)
        if flag == 0:
            number = str(random.randint(1, max_num-1))
        elif flag == 1:
            number = gen_fraction(max_num)
        elif flag == 2:
            number = str(random.randint(1, max_num-1)) + "‘" + gen_fraction(max_num)
    return number

e.生成表达式函数gen

首先定义一个空列表,生成一个数字,然后直接append进列表,append的效果是当成一个字符串传进去列表作为一个元素,从1到3随机取一个数,作为目前生成表达式中的符号数,注意这里的符号仅仅指加减乘除,循环完善表达式,数字->符号->数字,照这样的流程,直到满足足够的符号数。根据目前的具体情况,如果是只有一个符号,那么插入括号对是没有意义的,于是在这种情况下,选择不插入括号对;如果是两个符号,需要剔除括号对分别位于表达式两端这种情况;如果是三个符号,同样是剔除表达式两端这种情况。使用if语句确保右括号在左括号的右边,并且位置合理,最后形成的列表就是表达式,使用空格连接列表每一个元素,生成容易辨别的表达式字符串,将表达式列表传入计算函数,得到表达式的计算结果,将表达式字符串和计算结果作为一个Expression类实例的属性string和value返回

def gen(max_num):  # 生成表达式

    expression = []
    number = gen_number(max_num)
    expression.append(str(number))
    d = random.randint(1, 3)
    s = d
    while d > 0:
        symbol_flag = random.randint(1, 4)
        if symbol_flag == 1:
            expression.append("+")
        elif symbol_flag == 2:
            expression.append("-")
        elif symbol_flag == 3:
            expression.append("*")
        else:
            expression.append("÷")
        number = gen_number(max_num)
        expression.append(str(number))
        d = d - 1
    if s == 3:
        while True:
            left_flag = random.choice([0, 2, 4])
            right_flag = random.choice([2, 4, 6])
            if left_flag < right_flag and right_flag - left_flag != 6:
                expression.insert(left_flag, "(")
                expression.insert(right_flag+2, ")")
                break
    if s == 2:
        while True:
            left_flag = random.choice([0, 2])
            right_flag = random.choice([2, 4])
            if left_flag < right_flag and right_flag - left_flag != 4:
                expression.insert(left_flag, "(")
                expression.insert(right_flag + 2, ")")
                break
    string = " ".join(expression)
    value = calculate_all(expression)
    return Expression(string, value)

f.计算函数calculate

这个函数是用于计算一段表达式的值,首先将表达式里所有的带分数转假分数,使用假分数可以非常方便计算。首先判断目前这段表达式是否是只含有加减符号,如果是,则按序调用加减计算函数,这里提一个思路,是我们自身编程想到的,如果是单向计算,即目前表达式里面都是同一优先级的符号,那将目前的计算结果放在符号的下标加一,然后下次运算便可以基于目前的暂时结果继续加到运算中。同样,判断是不是只含有乘除符号,也使用同样的计算逻辑。如果不是前面两种情况,则证明存在不同优先级一起出现的情况,找出两个符号的下标值,优先计算优先级高的符号,将结果存放在高优先级符号的下标加减一处,然后再计算优先级低的符号

def calculate(str_list):  # 计算一段表达式的值

    i = 0
    while i < len(str_list):
        if str_list[i].count("‘") > 0:
            str_list[i] = reshape(str_list[i])
        i = i + 1
    if str_list.count("*") == 0 and str_list.count("÷") == 0:
        i = 0
        while i < len(str_list):
            if str_list[i] == "+":
                value = calculate_1(str_list[i - 1], str_list[i + 1])
                str_list[i + 1] = str(value)
            elif str_list[i] == "-":
                value = calculate_2(str_list[i - 1], str_list[i + 1])
                str_list[i + 1] = str(value)
            i = i + 1
    elif str_list.count("+") == 0 and str_list.count("-") == 0:
        i = 0
        while i < len(str_list):
            if str_list[i] == "*":
                value = calculate_3(str_list[i - 1], str_list[i + 1])
                str_list[i + 1] = str(value)
            elif str_list[i] == "÷":
                value = calculate_4(str_list[i - 1], str_list[i + 1])
                str_list[i + 1] = str(value)
            i = i + 1
    else:
        if str_list.count("÷") == 0:
            symbol_3_index = str_list.index("*")
            if str_list.count("-") == 0:
                symbol_1_index = str_list.index("+")
                value = calculate_3(str_list[symbol_3_index-1], str_list[symbol_3_index+1])
                str_list[symbol_3_index - 1] = value
                str_list[symbol_3_index + 1] = value
                value = calculate_1(str_list[symbol_1_index-1], str_list[symbol_1_index+1])
            else:
                symbol_2_index = str_list.index("-")
                value = calculate_3(str_list[symbol_3_index-1], str_list[symbol_3_index+1])
                str_list[symbol_3_index - 1] = value
                str_list[symbol_3_index + 1] = value
                value = calculate_2(str_list[symbol_2_index-1], str_list[symbol_2_index+1])
        else:
            symbol_4_index = str_list.index("÷")
            if str_list.count("-") == 0:
                symbol_1_index = str_list.index("+")
                value = calculate_4(str_list[symbol_4_index-1], str_list[symbol_4_index+1])
                str_list[symbol_4_index - 1] = value
                str_list[symbol_4_index + 1] = value
                value = calculate_1(str_list[symbol_1_index-1], str_list[symbol_1_index+1])
            else:
                symbol_2_index = str_list.index("-")
                value = calculate_4(str_list[symbol_4_index-1], str_list[symbol_4_index+1])
                str_list[symbol_4_index - 1] = value
                str_list[symbol_4_index + 1] = value
                value = calculate_2(str_list[symbol_2_index-1], str_list[symbol_2_index+1])
    return value

g.加法计算函数calculate_1

首先判断加数中是否有"False",如果有,就直接返回"False",这里先不展开解释"False"的出现。判断数中是否有斜杠,即是否为分数,由于前面有将带分数全部转为分数,所以数只有两种可能,整数和分数,如果是整数,则令分母为1,加法的计算结果为分子1x分母2+分子2x分母1除以分母1x分母2,将结果进行约分,如果分母是1,则直接输出分子,如果分母和分子相等,则输出1

def calculate_1(num_1, num_2):  # 加法运算

    if num_1.find("False") > -1 or num_2.find("False") > -1:
        return "False"
    if num_1.find("/") > -1:
        son_1 = int(num_1.split("/")[0])
        mother_1 = int(num_1.split("/")[1])
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2 + son_2 * mother_1
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2 + son_2 * mother_1
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == mother_3:
                number = 1
    else:
        son_1 = int(num_1)
        mother_1 = 1
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2 + son_2 * mother_1
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2 + son_2 * mother_1
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if mother_3 == 1:
                number = str(son_3)
            if son_3 == mother_3:
                number = 1
    return str(number)

h.减法计算函数calculate_2

首先判断加数中是否有"False",如果有,就直接返回"False",这里展开解释"False"的出现,由于题目要求如果出现减法,则不能出现复数,所以如果计算过程中出现num_1小于num_2,则返回"False"。判断数中是否有斜杠,即是否为分数,由于前面有将带分数全部转为分数,所以数只有两种可能,整数和分数,如果是整数,则令分母为1,加法的计算结果为分子1x分母2-分子2x分母1除以分母1x分母2,将结果进行约分,如果分子是0,则输出0,如果分母和分子相等,则输出1

def calculate_2(num_1, num_2):  # 减法运算

    if num_1.find("False") > -1 or num_2.find("False") > -1:
        return "False"
    if num_1.find("/") > -1:
        son_1 = int(num_1.split("/")[0])
        mother_1 = int(num_1.split("/")[1])
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2 - son_2 * mother_1
            if son_3 < 0:
                return "False"
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2 - son_2 * mother_1
            if son_3 < 0:
                return "False"
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    else:
        son_1 = int(num_1)
        mother_1 = 1
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2 - son_2 * mother_1
            if son_3 < 0:
                return "False"
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2 - son_2 * mother_1
            if son_3 < 0:
                return "False"
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    return str(number)

i.乘法计算函数calculate_3

首先判断加数中是否有"False",如果有,就直接返回"False"。判断数中是否有斜杠,即是否为分数,由于前面有将带分数全部转为分数,所以数只有两种可能,整数和分数,如果是整数,则令分母为1,加法的计算结果为分子1x分子2除以分母1x分母2,将结果进行约分,如果分子是0,则输出0,如果分母和分子相等,则输出1

def calculate_3(num_1, num_2):  # 乘法运算

    if num_1.find("False") > -1 or num_2.find("False") > -1:
        return "False"
    if num_1.find("/") > -1:
        son_1 = int(num_1.split("/")[0])
        mother_1 = int(num_1.split("/")[1])
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * son_2
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * son_2
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    else:
        son_1 = int(num_1)
        mother_1 = 1
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * son_2
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * son_2
            mother_3 = mother_1 * mother_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    return str(number)

j.除法计算函数calculate_4

首先判断加数中是否有"False",如果有,就直接返回"False"。如果num_2为0,同样返回"False"。判断数中是否有斜杠,即是否为分数,由于前面有将带分数全部转为分数,所以数只有两种可能,整数和分数,如果是整数,则令分母为1,加法的计算结果为分子1x分母2除以分母1x分子2,将结果进行约分,如果分子是0,则输出0,如果分母和分子相等,则输出1

def calculate_4(num_1, num_2):  # 除法运算

    if num_1.find("False") > -1 or num_2.find("False") > -1:
        return "False"
    if num_2 == "0":
        return "False"
    if num_1.find("/") > -1:
        son_1 = int(num_1.split("/")[0])
        mother_1 = int(num_1.split("/")[1])
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2
            mother_3 = mother_1 * son_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2
            mother_3 = mother_1 * son_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    else:
        son_1 = int(num_1)
        mother_1 = 1
        if num_2.find("/") > -1:
            son_2 = int(num_2.split("/")[0])
            mother_2 = int(num_2.split("/")[1])
            son_3 = son_1 * mother_2
            mother_3 = mother_1 * son_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
        else:
            son_2 = int(num_2)
            mother_2 = 1
            son_3 = son_1 * mother_2
            mother_3 = mother_1 * son_2
            number = str(son_3) + "/" + str(mother_3)
            number = reduce(number)
            if son_3 == 0:
                number = 0
            if son_3 == mother_3:
                number = 1
    return str(number)

k.带分数转分数函数reshape

取出带分数的整数部分,乘以分母加上分子得到新的分子,将新的分子与分母组成分数返回,可以用来将表达式中的所有带分数转为分数

def reshape(num_str):  # 从带分数转换成分数

    int_0 = num_str.split("‘")[0]
    son_0 = num_str.split("‘")[1].split("/")[0]
    mother_0 = num_str.split("‘")[1].split("/")[1]
    son_1 = int(int_0) * int(mother_0) + int(son_0)
    number = str(son_1) + "/" + str(mother_0)
    return number

l.计算表达式值函数calculate_all

首先判断目前的表达式是否含有括号对,如果有括号对,将括号对内的表达式片段取出,成为子表达式,然后调用calculate函数计算子表达式的结果,计算出表达式的结果后,将结果与括号对左括号前面的表达式片段、括号对右括号后面的表达式片段,组成新的一条表达式,再次调用calculate函数计算目前的结果,即得到整条表达式的结果

def calculate_all(str_list):  # 计算整个表达式的值

    if str_list.count("(") == 0:
        value = calculate(str_list)
    else:
        left_index = str_list.index("(")
        right_index = str_list.index(")")
        sub_str_list_1 = str_list[left_index + 1:right_index]
        value = calculate(sub_str_list_1)
        if value:
            sub_str_list_2 = str_list[0:left_index] + [value] + str_list[right_index + 1:len(str_list)]
            value = calculate(sub_str_list_2)
    if value:
        if value.count("/") > 0:
            string = str(value)
            son_0 = string.split("/")[0]
            mother_0 = string.split("/")[1]
            int_0 = int(son_0) // int(mother_0)
            son_0 = int(son_0) % int(mother_0)
            fraction = str(son_0) + "/" + str(mother_0)
            fraction = reduce(fraction)
            if int_0 == 0:
                value = fraction
            else:
                value = str(int_0) + "‘" + fraction
    return value

m.表达式类Expression

为生成工作函数定义一个类,类含有两个属性,一个是string属性,也就是前面所提到的容易辨别的表达式字符串,一个是value属性,也就是表达式的计算结果

class Expression:  # 定义一个表达式的类 含有表达式和值两个属性
    
    def __init__(self, string, value):
        self.string = string
        self.value = value

n.生成工作函数gen_work

首先打开指定的保存文件,Exercises.txt和Answers.txt作为指定的存放路径,使用Expression类的string属性用于区分目前生成的表达式是否有重复,如果value值不是"False"并且没有重复,则可以将目前生成的表达式实例加入列表,列表进行一个随机打乱后按序写入保存文件,最后输出一个tip,已生成指定道指定最大值以内的四则运算题,并将tip返回

def gen_work(expression_num, max_num):  # 生成表达式并计算表达式的值 后存放进指定文件

    expression_write = open("Exercises.txt", "w")
    answer_write = open("Answers.txt", "w")
    expression_list = []
    i = 0
    while i < 64:
        expression_list.append([])
        i += 1
    i = 0
    while i < expression_num:
        expression = gen(max_num)
        pass_repeat = len(list(filter(lambda X: X.string == expression.string,
                                      expression_list[len(expression.string)]))) == 0
        if expression.value != "False" and pass_repeat:
            expression_list[len(expression.string)].append(expression)
            i += 1
    expressions = []
    for expression in expression_list:
        expressions.extend(expression)
    random.shuffle(expressions)
    all_expression = ""
    all_answer = ""
    for i in range(len(expressions)):
        all_expression += (str(i+1) + "、\n" + expressions[i].string + " =\n")
        all_answer += (str(i+1) + "、\n" + expressions[i].value + '\n')
    expression_write.write(all_expression)
    answer_write.write(all_answer)
    expression_write.close()
    answer_write.close()

    tip = "已生成 " + str(expression_num) + " 道 " + str(max_num) + " 以内的四则运算题 题目存放于Exercises.txt 答案存放于Answers.txt"
    print(tip)
    return tip

o.检查工作函数check_work

首先打开指定的文件,首先获取答案文件的行数,由于写入语句的编写,所以答案文件的函数除以2就是题目的数量,使用readline读取两份答案文件的下一行,跳过题序行,比较答案行的内容,如果内容相同,则将目前的题序存入正确列表,如果不同,则存入错误列表,tip_1是正确的数量与题序,tip_2是错误的数量与题序,tip_3是tip_1和tip_2加上一句成绩存放于Grade.txt,将tip_3写入Grade.txt并返回tip_3

def check_work(answer_path, test_path):  # 检查答案文件与测试文件的差别 统计正确和错误情况

    answer = open(answer_path, "r")
    test = open(test_path, "r")
    count = len(open(answer_path, "r").readlines())
    true_list = []
    false_list = []
    i = 0
    while i < count/2:
        answer.readline()
        test.readline()
        if answer.readline() == test.readline():
            true_list.append(str(i+1))
        else:
            false_list.append(str(i+1))
        i = i + 1
    tip_1 = "Correct: " + str(len(true_list)) + " (" + ", ".join(true_list) + ")"
    tip_2 = "Wrong: " + str(len(false_list)) + " (" + ", ".join(false_list) + ")"
    print(tip_1)
    print(tip_2)
    tip_3 = tip_1 + "\n" + tip_2 + "\n成绩存放于Grade.txt"
    grade_path = "Grade.txt"
    grade = open(grade_path, "w")
    grade.write(tip_3)
    grade.close()
    return tip_3

p.按钮链接生成工作函数bitter_gen_work

从图形界面中获取题目数量expression_num和最大值max_num,调用生成工作函数,传入参数,并获得返回的tip,将tip回显到图形界面的文本框中

def bitter_gen_work():  # 提供给按钮链接 生成表达式并计算表达式的值 后存放进指定文件

    expression_num = expression_num_input.get()
    max_num = max_num_input.get()
    expression_num = int(expression_num)
    max_num = int(max_num)
    tip = gen_work(expression_num, max_num)
    message.insert(END, "\n" + tip + "\n")

q.按钮链接检查工作函数bitter_check_work

从图形界面中获取答案文件路径answer_path和测验文件路径test_path,调用检查工作函数,传入参数,并获得返回的tip,将tip回显到图形界面的文本框中

def bitter_check_work():  # 提供给按钮链接 检查答案文件与测试文件的差别 统计正确和错误情况

    answer_path = answer_path_input.get()
    test_path = test_path_input.get()
    tip = check_work(answer_path, test_path)
    message.insert(END, "\n" + tip + "\n")

r.主函数main

定义图形化界面的大小,标题,提示信息,四个输入框,两个按钮和一个文本框,输入框用于获取输入参数,按钮链接对应的工作函数,文本框用于回显tip

if __name__ == '__main__':  # 定义图形界面

    root = Tk()
    root.geometry('550x330')
    root.title('bitter的四则运算生成/检查器')

    explain = Label(root, text='请输入四个参数 分别为"expression_num" "max_num" "answer_path" "test_path"')
    explain.place(relx=0.075, rely=0.05, relwidth=0.85, relheight=0.1)
    expression_num_input = Entry(root)
    expression_num_input.place(relx=0.1, rely=0.2, relwidth=0.3, relheight=0.1)
    max_num_input = Entry(root)
    max_num_input.place(relx=0.1, rely=0.35, relwidth=0.3, relheight=0.1)
    answer_path_input = Entry(root)
    answer_path_input.place(relx=0.1, rely=0.5, relwidth=0.3, relheight=0.1)
    test_path_input = Entry(root)
    test_path_input.place(relx=0.1, rely=0.65, relwidth=0.3, relheight=0.1)

    commit_1 = Button(root, text='开始生成', command=bitter_gen_work)
    commit_1.place(relx=0.6, rely=0.275, relwidth=0.3, relheight=0.1)
    commit_2 = Button(root, text='开始检查', command=bitter_check_work)
    commit_2.place(relx=0.6, rely=0.575, relwidth=0.3, relheight=0.1)

    message = Text(root)
    message.place(rely=0.8, relheight=0.2)

    root.mainloop()

6.测试运行

在test.py中编写了10个不同的表达式,其中包含两个"False"样本,这种样本生成后检验是会被筛选掉的,调用calculate_all函数计算结果,人工对比答案,记录目前答案的置信度,使用"coverage run test.py"进行单元测试并记录代码覆盖率,使用"coverage report"读取前面保存的.coverage文件,输出覆盖率

if __name__ == '__main__':

    expression_list = ["1", "+", "2/3", "-", "1‘1/3"]
    print("1、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "x", "2/3", "÷", "1‘1/3"]
    print("2、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "+", "2/3", "*", "1‘1/3"]
    print("3、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["(", "1", "+", "2/3", ")", "*", "1‘1/3"]
    print("4、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "÷", "2/3", "+", "1‘1/3"]
    print("5、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "÷", "(", "2/3", "+", "1‘1/3", ")"]
    print("6、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["(", "1", "÷", "2/3", "+", "1‘1/3", ")", "*", "3"]
    print("7、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "÷", "(", "2/3", "+", "1‘1/3", "*", "3", ")"]
    print("8、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "-", "2/3", "-", "1‘1/3"]  # False样本
    print("9、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

    expression_list = ["1", "÷", "(", "2/3", "-", "2/3", ")"]  # False样本
    print("10、" + " ".join(expression_list) + "=")
    value = calculate_all(expression_list)
    print(value)

这里做一个补充说明,因为是全部函数都放在bitter_work.py文件,并且测试的时候仅用到了与计算函数相关的函数,所以覆盖率偏低属于正常情况

img

7.异常说明

1.文件路径错误

正常的文件路径参数应该是指向存在并且能比较的文件,但如果在输入参数的时候,输错了文件名,则报错FileNotFoundError,这个时候只要重新确认参数就可以了

img

8.项目小结

图形界面使用实例展示,如下图

img

...全文
77 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

203

社区成员

发帖
与我相关
我的任务
社区描述
高校教学社区
其他 高校 广东省·广州市
社区管理员
  • ryue.zh
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧