第三次作业第二版

from prettytable import PrettyTable
import numpy, os, sys, termios

# 打印菜单
def printMenu():
    menu = '''
************欢迎进入学生成绩管理系统*****************
                    菜单
输入成绩-------------------------------------------------1
查看成绩及成绩排序---------------------------------------2
查询学生成绩---------------------------------------------3
成绩统计-------------------------------------------------4
修改成绩-------------------------------------------------5
添加成绩-------------------------------------------------6
删除成绩-------------------------------------------------7
保存成绩-------------------------------------------------8
退出系统-------------------------------------------------9
*******************************************************
'''
    print(menu)

# 按任意键继续
def press_any_key_exit(msg):
    fd = sys.stdin.fileno()
    old_ttyinfo = termios.tcgetattr(fd)
    new_ttyinfo = old_ttyinfo[:]
    new_ttyinfo[3] &= ~termios.ICANON
    new_ttyinfo[3] &= ~termios.ECHO
    sys.stdout.write(msg)
    sys.stdout.flush()
    termios.tcsetattr(fd, termios.TCSANOW, new_ttyinfo)
    os.read(fd, 7)
    termios.tcsetattr(fd, termios.TCSANOW, old_ttyinfo)
    print('')

# 防止误输入,设置0<=成绩<=100,并判断输入计算平均成绩:
def foolProof(score):
    # 判断格式正确返回True,错误返回false
    if score.isdigit() and 0 <= eval(score) <= 100:
        return True
    else:
        return False

def inportScore():
    dic_score = dict()
    while True:
        dic_score['数学'] = input("请输入数学成绩:")
        dic_score['英语'] = input("请输入英语成绩:")
        dic_score['计算机'] = input("请输入信息成绩:")
        if foolProof(dic_score['数学']) and foolProof(dic_score['英语']) and foolProof(dic_score['计算机']):  # 调用判断函数,若全为True则跳出循环,返回成绩字典,否则重新输入
            break
        else:
            print('请输入正确的成绩!')
    dic_score['平均成绩'] = '%.2f' % ((float(dic_score['数学']) + float(dic_score['英语']) + float(dic_score['计算机']))/3)
    return dic_score

# 防止学号录入重复
def inputStudentNum():
    while True:
        studentNum = input("请输入学号:")
        if studentNum.isdigit():
            if searchScore(studentNum):  # 调用查询成绩函数,若是查询到了说明学号重复,说明学生信息已经录入,需要重新输入学号
                print('您输入的学号已存在,请重新输入!')
            else:
                return studentNum  # 若不存在,则返回学号
        else:
            print('您输入的学号格式不对,请重新输入!')

# 录入信息
def inputStudentInfo():
    dic = dict()
    dic['学号'] = inputStudentNum()  # 调用函数检查学号是否已经存在
    dic['姓名'] = input("请输入学生姓名:")
    dic_score = inportScore()  # 调用函数检查成绩是否输入是否合规
    studentInfo = dict(dic,**dic_score)  # 合并字典
    return studentInfo

# 读取学生信息
def readDB():
    with  open('db', 'r') as f:
        students_info = f.readlines()
        for i in range(len(students_info)):
            students_info[i] = students_info[i].rstrip('\n')  # 去掉行尾换行
            students_info[i] = eval(students_info[i])
    return students_info

# 排序计算名次
def takeSecond(elem):
    return float(elem['平均成绩'])

def studentsSort(students_info,*args):
    # 可以接受一个或者多个参数,原因是在学生信息录入的时候需要读出数据库中的数据作为第一个参数,将录入的作为第二个参数
    # 在删除或者修改学生信息的时候,只需要将删除或者修改后的学生信息传过来即可,此时为1个参数
    if args:
        students_info.append(args[0])  # 若为录入,此时将录入的学生信息追加到学生信息总表中,方便排序
    students_info.sort(key=takeSecond, reverse=True)  # 按照平均成绩进行排序
    for i in range(len(students_info)):
        students_info[i].update({'名次': i + 1})  # 将排序编号作为名次更新到字典中
    return students_info

# 写入学生成绩信息
def writeDB(students_info):
    # 此处写入全为覆盖写,原因是追加不方便排序,反正都是要将信息全部读取出来排序,就不需要复杂的文件操作了,但是有点浪费内存,有优化空间
    with open('db', 'w') as f:
        for student_info in students_info:
            f.write(str(student_info))
            f.write('\n')

# 查询学生信息
def searchScore(student_number):
    # 查询指定学生的信息,并返回一个字典
    students_info = readDB()
    for student_info in students_info:
        if student_info['学号'] == student_number:
            return student_info

# 判断学生成绩在哪个区间,不及格返回0,优秀返回1
def scoreLevel(score):
    # 这里不需要做及格的判断,因为除开不及格的就是及格的
    if score < 60:
        return 0
    else:
        if score >= 90:
            return 1

# 保存确认
def confirmSave(students_info):
    while True:
        save_modify = input('是否保存您的修改<y/n>:')
        if save_modify == 'y':
            students_info = studentsSort(students_info)  # 调用排序函数进行排序
            writeDB(students_info)  # 将排序完的数据写入DB
            print('保存成功!')
            break
        elif save_modify == 'n':
            break
        else:
            print('请重新输入。')  # 不是输入y/n的时候就重新输入

# 格式化输出表格,包括排名
def printOut(students_info):
    table = PrettyTable(['学号', '姓名', '数学', '英语', '计算机', '平均成绩', '名次'])  # 输入表头
    for student_info in students_info:
        # 按照key添加行
        table.add_row([student_info['学号'],student_info['姓名'],student_info['数学'],student_info['英语'],student_info['计算机'],student_info['平均成绩'],student_info['名次']])
    table.reversesort = True
    print(table)

# 格式化输出表格,不包括排名
def printOut1(students_info):
    # 这是在修改学生成绩的时候显示,此时不需要显示名次,因为此时没有调用排序函数,显示的名次不准确,所以去掉
    table = PrettyTable(['学号', '姓名', '数学', '英语', '计算机', '平均成绩'])
    for student_info in students_info:
        table.add_row([student_info['学号'],student_info['姓名'],student_info['数学'],student_info['英语'],student_info['计算机'],student_info['平均成绩']])
    table.reversesort = True
    print(table)

# 下面开始各个功能项的实现
# 1.输入成绩
def writeStudentInfo():
    input_student_info = inputStudentInfo()
    old_students_info = readDB()
    new_student_info = studentsSort(old_students_info, input_student_info)
    writeDB(new_student_info)
    print("录入学生成绩成功!")

# 2.查看学生成绩以及成绩排名
def readStudentsInfo():
    students_info = readDB()
    printOut(students_info)

# 3.查询学生成绩
def searchStudentScore():
    student_number = input('请输入需要查询的学生学号:')
    student_info = searchScore(student_number)
    if student_info:
        printOut([student_info])
    else:
        print("你查询的学生不存在!")

# 4.成绩统计
#  4.1 及格率
def scoreStat():
    students_info = readDB()
    no_pass_counts = 0
    excellent_counts = 0
    ave_score_list = list()  #获取平均成绩列表
    for student_info in students_info:
        score = float(student_info['平均成绩'])
        ave_score_list.append(score)
        if scoreLevel(score) == 0:  #统计不及格人数
            no_pass_counts += 1
        elif scoreLevel(score) == 1:  #统计优秀人数
            excellent_counts += 1
    total_counts = len(students_info)
    #计算及格率
    pass_rate = 1 - no_pass_counts/total_counts
    pass_rate = '%.2f%%' % (100 * pass_rate)
    #计算优秀率
    excellent_rate = excellent_counts/total_counts
    excellent_rate = '%.2f%%' % (100 * excellent_rate)
    #计算方差和标准差
    ave_score_var = numpy.var(ave_score_list)
    ave_score_var = '%.2f' % ave_score_var
    ave_score_std = numpy.std(ave_score_list,ddof=1)
    ave_score_std = '%.2f' % ave_score_std
    #进行输出
    print('整体及格率为:{}'.format(pass_rate))
    print('整体优秀率为:{}'.format(excellent_rate))
    print('整体方差为:{}'.format(ave_score_var))
    print('整体标准差为:{}'.format(ave_score_std))
             
# 5.修改成绩
def modifyStudentScore():
    student_number = input('请输入需要修改的学生学号:')
    print(student_number)
    students_info = readDB()
    j = 1  # 这个j是用来判断学号存不存在,存在就减一
    for i in range(len(students_info)):
        if students_info[i]['学号'] == student_number:
            printOut1([students_info[i]])
            print('请重新输入该学生成绩:')
            dic_score = inportScore()
            for key in dic_score.keys():
                students_info[i][key] = dic_score[key]
            print('修改成功,修改后的成绩为:')
            printOut1([students_info[i]])
            confirmSave(students_info)
            j -= 1
            break
    if j:  # 如果没有减一,就说明学号不存在,此处不让他重新输入学号,担心他忘记了学号一直退不出循环
        print("您输入的学号不存在!")
# 6.添加成绩同1
    # 这个功能没有明白他的意思,是要添加一个人的信息,还是要添加新的一科成绩,要是添加新的一科,这个程序需要重构
    # 若是添加一个人的成绩,那同1,要是修改某人成绩,则同5

# 7.删除成绩
def deleteStudentInfo():
    student_number = input('请输入需要修改的学生学号:')
    print(student_number)
    students_info = readDB()
    j = 1  # 判断学号是否存在
    for student_info in students_info:
        if student_info['学号'] == student_number:
            j -= 1
            printOut([student_info])  # 打印出要删除的学生信息,防止删错了
            while True:
                delete_info = input('是否删除该学生成绩<y/n>:')
                if delete_info == 'y':
                    students_info.remove(student_info)
                    break
                elif delete_info == 'n':
                    break
                else:
                    print('请重新输入。')
            confirmSave(students_info)
    if j:
        print("您输入的学号不存在!")
# 8.保存成绩,成绩自动保存无需保存成绩

# 9.退出系统

def main():
    #打印导航菜单,并获取用户选择信息
    printMenu()

    while True:
        number = input("请输入您的选择:")

        if number == '1':  # 输入成绩
            writeStudentInfo()
        elif number == '2':  # 查看成绩以及成绩排名
            readStudentsInfo()
        elif number == '3':  # 查询某个学生成绩
            searchStudentScore()
        elif number == '4':  # 成绩统计
            scoreStat()
        elif number == '5':  # 修改成绩
            modifyStudentScore()
        elif number == '6':  # 添加成绩
            writeStudentInfo()
        elif number == '7':  # 删除成绩
            deleteStudentInfo()
        elif number == '8':  # 保存成绩
            print('保存成功!')
        elif number == '9':  # 退出系统
            print("退出成功!")
            exit()
        else:
            print("输入错误,请重新输入!")
        press_any_key_exit("按任意键继续...")

if __name__ == '__main__':
    main()

 

posted on 2021-05-16 21:09  torotoise512  阅读(62)  评论(0)    收藏  举报