结对编程代码分析

结对编程代码分析

该同学用python语言实现中小学生试卷生成系统。

一、项目结构:

image

  • letters1~letters9依次存放张三1到王五3的过往试卷,create.py为项目的主程序,userData.json 存放用户数据

  • userData.json内容如图:
    image

    • 每个用户存有三个属性,account是为用户名,password为密码,grade为用户的预设年级。

二、主程序代码分析:

  • 参数及主要函数总览:

image

  • login()函数:

    # 用于处理用户登录操作的函数
    def login():
        get: list[str] = []
        flag: bool = False # 标识是否登录成功
        while 1:
            if flag:
                get = input("请输入正确的用户名、密码:").split(' ')#空格分隔
            elif not flag:
                get = input("请输入用户名、密码:").split(' ')
                flag = True
    
            for y in user_lib:
                if get[0] == user_lib[y]['account'] and get[1] == user_lib[y]['password']:
                    return {'uid': y, 'grade': user_lib[y]['grade']}
    
  • create_problem()函数:

    # 用于生产单行题目的函数
    def create_problem(grade: str):
        question: str = ''  # 返回值
        length: int = randint(2, 5)  # 可操作数的个数 考虑到实际情况,不可能只有一个操作数。
        # print(f"length:{length}")  # 注释掉
        num_square = randint(1, length)  # 有几个数被赋予特殊符号(开方和平方)
        num_tangle = randint(1, length)  # 有几个数被赋予特殊符号(三角函数)
        # print(f"num:{num_square}")  # 注释掉
        data_lib: list[int] = []  # 给操作数编号,为了保证随机时不出现重复数值,使用数组
        for i in range(0, length):
            data_lib.append(i + 1)
        # print(f"data_lib:{data_lib}")  # 注释掉
        square_map: dict = {}
        tangle_map: dict = {}
        leftbracket: int = 0  # 计数
        leftbracket_flag: bool = False  #
        no_double_bracket: bool = False  # 防止出现(x)的情况
        # 变量定义————————————————————————————————————————————————
    
        if grade == 'primary':  # 还未设计添加括号进去
            for i in range(0, length):
                no_double_bracket = False
                if randint(0, 1) == 1 and length > 2 and i != length - 1:  # 随机生成左括号
                    question += '('
                    leftbracket += 1
                    leftbracket_flag = True
                    no_double_bracket = True
                if i == length - 1:  # 只剩一个数了,不用再加符号了
                    question += f"{randint(1, 100)}"
                    for i in range(0, leftbracket):  # 补全括号部分
                        question += ')'
                    question += '=\n'
                    # if check_string(re_exp, question):# 为了避免等式两端出现括号
                    #     return re.findall(re_exp, question)[0]+'\n'
                    # else:
                    #     return question
                    return question
                question += f"{randint(1, 100)}"
    
                for i in range(0, leftbracket):  # 随机补全右括号
                    if randint(0, 1) == 1 and leftbracket_flag and not no_double_bracket:
                        question += ')'
                        leftbracket -= 1
                        if leftbracket == 0:
                            leftbracket_flag = False
                question += f"{symbol_lib[randint(0, 3)]}"
        # 小学题目————————————————————————————————————————————————
    
        elif grade == 'junior':
            for i in range(0, len(data_lib)):  # 给随机几位操作数生成
                a = randint(0, len(data_lib) - 1)  # 0对应1,1对应2,2对应3,3对应4
                symbol_index = randint(4, 5)
                # print(data_lib[a])
                square_map[data_lib[a]] = symbol_lib[symbol_index]
                data_lib.pop(a)
                num_square -= 1
                if num_square == 0:
                    break
            # print(square_map)
    
            for i in range(0, length):
                no_double_bracket = False
                if randint(0, 1) == 1 and length > 2 and i != length - 1:  # 随机生成左括号
                    question += '('
                    leftbracket += 1
                    leftbracket_flag = True
                    no_double_bracket = True
    
                if i == length - 1:  # 只剩一个数了,不用再加符号了
                    if square_map.__contains__(i + 1):  # dict里面有和i对应的键值,说明需要加平方或者开方
                        question += f"({randint(1, 100)}{square_map[i + 1]})"  # 决定暂时给平方、开方加上括号
                    else:
                        question += f"{randint(1, 100)}"
                    for i in range(0, leftbracket):  # 补全括号部分
                        question += ')'
                    question += '=\n'
                    # if check_string(re_exp, question):  # 为了避免等式两端出现括号
                    #     return re.findall(re_exp, question)[0] + '\n'
                    # else:
                    #     return question
                    return question
    
                r: str = symbol_lib[randint(0, 3)]
                if square_map.__contains__(i + 1):
                    question += f"({randint(1, 100)}{square_map[i + 1]})"  # 决定暂时给平方、开方加上括号
                else:
                    question += f"{randint(1, 100)}"
    
                for i in range(0, leftbracket):  # 随机补全右括号
                    if randint(0, 1) == 1 and leftbracket_flag and not no_double_bracket:
                        question += ')'
                        leftbracket -= 1
                        if leftbracket == 0:
                            leftbracket_flag = False
                question += f"{r}"
        # 初中题目————————————————————————————————————————————————
    
        elif grade == 'senior':
            num_square = randint(0, length)
            for i in range(0, len(data_lib)):  # 给随机几位操作数生成
                a = randint(0, len(data_lib) - 1)
                symbol_index = randint(4, 5)
                # print(data_lib[a])
                square_map[data_lib[a]] = symbol_lib[symbol_index]
                data_lib.pop(a)
                num_square -= 1
                if num_square == 0:
                    break
            # print(square_map)  # 注释掉
    
            data_lib = []  # 为tangle的判定重置data_lib
            for i in range(0, length):
                data_lib.append(i + 1)
            for i in range(0, len(data_lib)):  # 给随机几位操作数生成
                a = randint(0, len(data_lib) - 1)
                symbol_index = randint(6, 8)
                tangle_map[data_lib[a]] = symbol_lib[symbol_index]
                data_lib.pop(a)
                num_tangle -= 1
                if num_tangle == 0:
                    break
            # print(tangle_map)  # 注释掉
    
            for i in range(0, length):
                no_double_bracket = False
                if randint(0, 1) == 1 and length > 2 and i != length - 1:  # 随机生成左括号
                    question += '('
                    leftbracket += 1
                    leftbracket_flag = True
                    no_double_bracket = True
    
                if i == length - 1:  # 只剩一个数了,不用再加符号了
                    if square_map.__contains__(i + 1) and tangle_map.__contains__(i + 1):  # dict里面有和i对应的键值,说明需要加平方或者开方
                        question += f"{tangle_map[i + 1]}({randint(1, 100)}{square_map[i + 1]})"
                    elif square_map.__contains__(i + 1) and not tangle_map.__contains__(i + 1):
                        question += f"({randint(1, 100)}{square_map[i + 1]})"
                    elif not square_map.__contains__(i + 1) and tangle_map.__contains__(i + 1):
                        question += f"{tangle_map[i + 1]}({randint(1, 100)})"
                    else:
                        question += f"{randint(1, 100)}"
                    for i in range(0, leftbracket):  # 补全括号部分
                        question += ')'
                    question += '=\n'
                    return question
    
                r: str = symbol_lib[randint(0, 3)]
                if square_map.__contains__(i + 1) and tangle_map.__contains__(i + 1):  # dict里面有和i对应的键值,说明需要加平方或者开方
                    question += f"{tangle_map[i + 1]}({randint(1, 100)}{square_map[i + 1]})"
                elif square_map.__contains__(i + 1) and not tangle_map.__contains__(i + 1):
                    question += f"({randint(1, 100)}{square_map[i + 1]})"
                elif not square_map.__contains__(i + 1) and tangle_map.__contains__(i + 1):
                    question += f"{tangle_map[i + 1]}({randint(1, 100)})"
                else:
                    question += f"{randint(1, 100)}"
                for i in range(0, leftbracket):  # 随机补全右括号
                    if randint(0, 1) == 1 and leftbracket_flag and not no_double_bracket:
                        question += ')'
                        leftbracket -= 1
                        if leftbracket == 0:
                            leftbracket_flag = False
                question += f"{r}"
        # 高中题目————————————————————————————————————————————————
        return question
    
  • change_grade()函数:

    # 用于切换当前用户出题年级的函数
    def change_grade(change: str):
        if change in {'小学', '初中', '高中'}:
            return base[change]
        while 1:
            change = input("请输入小学、初中和高中三个选项中的一个:").split("切换为")[0]
            if change in {'小学', '初中', '高中'}:
                return base[change]
    
  • print_letter()函数:

    # 用于输出试卷到txt文件的函数
    def print_letter(uid: str, key: str, number: int):
        file_url = f"./letters{uid}/{datetime.now().strftime('%Y%m%d%H%M%S')}.txt"  
        # 使用datatime类的now()函数获取当前时间
        # %Y%m%d%H%M%S 格式化选择输出
        question: str
        file = open(file_url, 'w+')
        for i in range(0, number):
            while 1:
                question = create_problem(key) # 调用试题生成函数
                if check_in_history_letters(uid, question):
                    break
                else:
                    pass
            question += '\n'
            file.write(question)
        file.close()
        return f"********已生成{file_url}********"
    
  • read_history_letters()函数:

    # 用于读取老师出题历史记录的函数
    def read_history_letters(uid: str):
        dir_url = f'letters{uid}'
        question_list: list[str] = []
        files: list[str] = []
        for root, dirs, files in os.walk(dir_url, topdown=False):
            # root 根目录、dirs 子目录、files 子目录里的文件
            # print(files)  # 注释掉
            pass
        for file in files:  # 遍历目录里的txt文件
            f = open(f'./{dir_url}/{file}', 'r')
            for line in f:  # 遍历文件的每一行
                if line != '\n':
                    question_list.append(line.split('\n')[0])  # 去除换行转义字符
        question_dict[uid] = question_list
        # print(question_dict)  # 注释掉
    
  • check_in_history_letters()函数:

    # 用于检查题目是否已经出现过的函数
    def check_in_history_letters(uid: str, question: str):
        if question_dict[uid].__contains__(question):
            return False
        else:
            return True
    
  • main函数

    # 程序运行的主函数
    if __name__ == '__main__':
        user = login()
        key = user.get('grade')
        uid = user.get('uid')
        # print(datetime.now().strftime('%Y%m%d%H%M%S'))#注释掉
        print(f"当前选择为{base[key]}出题")
        read_history_letters(uid)  # 预先读取当前用户的题库
        while 1:
            change: str = ''
            number: int = 0
            error: bool = False
            print("********---********")
            get = input(f"准备生成{base[key]}数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):")
    
            if len(get.split("切换为")) == 2:
                change = get.split("切换为")[1]
                if change == '':
                    error = True
            else:
                try:
                    number = int(get)
                except ValueError:
                    error = True
            if number <= 30 and number >= 10:  # 10-30 正常输出
                print(print_letter(uid, key, number))
            elif get == '-1':  # -1重新登录(-1 的判断优先级必须高于 >30 or <10 的判断)
                user = login()
                uid = user.get('uid')
                key = user.get('grade')
                read_history_letters(uid)  # 同时更新key和uid
            elif change in {'小学', '初中', '高中'} and key != base[change]:  # 切换年级
                key = change_grade(change)
                print(f"当前选择为{base[key]}出题")
            elif error:
                print("请输入正确的指令,切换年级请输入\"切换为XX\"")
                pass
            elif number > 30 or number < 10:  # 超出题数范围,重新输入
                while 1:
                    get = input(f"准备生成{base[key]}数学题目,请在允许范围内输入生成题目数量(10-30之间):")
                    try:
                        number = int(get)
                        if number <= 30 and number >= 10 or number == -1:
                            break;
                    except ValueError:
                        pass
                if number != -1:
                    print(print_letter(uid, key, number))
            else:
                print("请输入正确的指令,切换年级请输入\"切换为XX\"")
                pass
    

三、代码优缺点分析:

  • 优点:

    • 分了多个函数实现功能,每个函数的作用明确,整体的结构清晰

    • 可拓展性强

      代码结构清晰,对各数据结构、函数进行了明确细致地划分,有利于后期功能拓展与项目扩大。

    • 文件路径使用相对路径,清晰明确。

  • 缺点:

    • 功能实现不完全:不能在三角函数、平方和开方的计算中掺杂复杂表达式(例如:tan(10+20)、(1+9)^2等等类似题目),无法生成

    • 括号的使用会出现冗余现象,指:

      (21-(11/(96+18)))=
      

      这种情况,计算式最外层出现的无意义括号。

四、生成结果展示:

image

  • 小学

    33/73-45+72=
    
    44/81=
    
    42-59=
    
    (1/30)-72*(26-40)=
    
    (44/67)+76*(14-47)=
    
    (21-(11/(96+18)))=
    
    65/(85/91*11-2)=
    
    32+(91-61)=
    
    26-(88/15)=
    
    89/13=
    
  • 初中

    (85-22*((65^0.5)/28))=
    
    51/15*(77^0.5)=
    
    (81^0.5)-(25^2)=
    
    ((51^0.5)*29*((96^0.5)+((87^2)*31)))=
    
    65-25-(36^2)=
    
    ((90^0.5)-(32/((75^0.5)-(66+(65^2)))))=
    
    (20/(67^2))-51=
    
    (35^2)-((65^0.5)-(60^2))/(68^0.5)+(73^2)=
    
    (59^0.5)+2=
    
    (54^0.5)*(75^2)=
    
  • 高中

    (tan(78^0.5)/tan(45^2))+(50^2)=
    
    tan(93^0.5)/(sin(27^2)-sin(37^2))=
    
    (88^2)/78/(tan(99^0.5)*(23+83))=
    
    tan(64^0.5)-(41^2)=
    
    (tan(68^0.5)/cos(96))/sin(34)=
    
    (sin(87^2)+cos(94^0.5)*(cos(35^2)+tan(30^0.5))+sin(2^0.5))=
    
    tan(20^0.5)*cos(23^2)=
    
    (92-((46^0.5)-(16+((92^0.5)-cos(91^2)))))=
    
    (99^2)-sin(100^2)=
    
    (29^2)-cos(3^0.5)/cos(22^0.5)=
    
posted @ 2022-09-14 11:01  ILonerEd  阅读(145)  评论(0)    收藏  举报