利用Python,如何将包含姓名和分数的文本文件添加额外信息?

40 阅读4分钟

我正在为学校数学课程编写一个简单的数学程序,孩子们在程序中输入姓名,然后程序会询问10个简单的数学问题。

  • 在程序结束后,孩子们分别按班级区分,姓名和分数将被存储在不同的文本文件中。
  • 我目前遇到的一些问题如下:
  • 我不确定是否有更好的方法来实现这个功能。
  • 如果同一个孩子再次参加测试,如何将分数与之前分数取平均值?
  • 如果孩子取得了更高的分数,如何使孩子的分数覆盖之前分数?(此处与平均分在不同的文本文件中)
  • 我想要创建一个排行榜,最高分的孩子在顶部,最低分的孩子在底部。
  • 当在排行榜上显示时,我希望它看起来像这样:
  • 威廉-威尔逊 - 10
  • 日向宁宁 - 9
  • 等等。
  • 我已经搜索了很多地方,但似乎找不到答案。如果有人能分享他们的知识,那就太好了。非常感谢!
  • 以下是我尚未完成的代码。我是Python新手。
  • 我需要在排行榜上添加额外的信息:平均分、最高分以及每个学生最高分对应测试的字母顺序。
  1. 解决方案
  • 为了解决您在Python中将信息添加到包含姓名和分数的文本文件的问题,我提供了一套完善的解决方案,其中包含详细的代码示例和说明:
  • 定义一个 entry 类来存储每个学生的姓名、总分、尝试次数和平均分等信息。
  • 使用 find_entry 函数在数据文件中查找学生的条目。
  • 利用 play 函数让学生参加测试并更新他们的分数。
  • 运用 leaderboard 函数生成并显示学生的排行榜。
  • 添加 backup 函数来定期备份数据文件,以防数据丢失。
  • 通过 add_student 函数向数据文件中添加新学生。
  • 以下是如何实现上述解决方案的方法:
  • 在Python环境中,复制并粘贴提供给您的代码。
  • 确保将 directory_name 变量的值替换为您希望存储数据文件的目录路径。
  • 确保正确填写备份文件的存储位置。
  • 运行Python程序。
  • 按照程序中的提示操作,输入学生姓名、参加测试并查看排行榜。

以下是代码示例:

import time, random, operator
directory_name = r"C:\Users\YOU\yourDirectoryHere\"
#When you change the directory name, be SURE to include
#the double backslash at the end. (and keep the r)
datafile = open(directory_name + "scores.txt")
data = bytearray(datafile.read())
datafile.close()

backup_directory = directory_name
def backup():
    #Note: I didn't explain this function. It just randomly
    #makes backups of the data file in case something unexpected happens.
    global data, backup_directory
    datafile = open(backup_directory + str(int(time.time())) + '.txt', 'w')
    datafile.write("Remove this timestamp, message, and newline before restoring this data %s\n" % time.asctime())
    datafile.write(data)
    datafile.close()

class entry():
    def __init__(self, i):
        #i is the location of the student's entry in the data.
        global data
        self.name = data[i:i + 30]
        self.total = int(data[i + 30:i + 40])
        self.attempts = int(data[i + 40:i + 49])
        if self.attempts:
            self.average = float(self.total) / self.attempts
        else: self.average = 0.0

    def __cmp__(self, other):
        #BUGGED CODE return self.average - other.average
        #FIXED BELOW
        if self.average > other.average: return 1
        elif self.average < other.average: return -1
        else: return 0

    def __str__(self):
        return "%s | %2.2f" % (self.name, self.average)

    def update_score(self, score, i):
        global data, directory_name
        self.total += score
        self.attempts += 1
        self.average = float(self.total) / self.attempts
        data[i + 30: i + 40] = "%10i" % self.total
        data[i + 40: i + 49] = "%9i" % self.attempts
        datafile = open(directory_name + "scores.txt",'w')
        datafile.write(data)
        datafile.close()

        if not random.randrange(5):
            backup()


def find_entry(name):
    global data
    for i in xrange(0,len(data),50):
        if data[i:i + 30] == "%30s" % name:
            return i
    print "Name not found. Please check the spelling of your name."
    print "If you spelled your name correctly please ask your teacher for help."
    return None

def question():
    n1 = random.randint(1,9)
    n2 = random.randint(1,9)
    ops = {'+': operator.add, '-': operator.sub, 'x': operator.mul}
    op = random.choice(ops.keys())
    answer = raw_input("What is %i %s %i?  " % (n1, op, n2))
    try: 
        answer = int(answer)
        if answer == ops[op](n1, n2):
            print "Well done"
            return 1
        else:
            print "incorrect, %i %s %i = %i" % (n1, op, n2, ops[op](n1,n2))
            return 0
    except:
        print "'%s' does not appear to be a number." % answer
        return 0

def play():
    global data
    entry_num = None
    while entry_num == None:
        entry_num = find_entry(raw_input("Please enter your name and surname initial (e.g. William G): "))

    student_entry = entry(entry_num)
    score = 0
    for i in xrange(10):
        score += question()

    student_entry.update_score(score, entry_num)
    print "Your score this time was %i / 10" % score

def leaderboard():
    global data
    entries = []
    for i in xrange(0, len(data),50):
        entries += [entry(i)]

    entries.sort()
    entries.reverse()

    for i in entries:
        print i

def add_student():
    #This wasn't explained either. It just appends a properly formatted 50 character
    #long entry to the bytearray, initialized with the inputted name and zeroes.
    global data
    while True:
        student = raw_input("Add a student, press enter to quit: ")
        if student:
            cancel = raw_input("Confirm '%s'. Press enter to confirm, any key to cancel: " % student)
            if not cancel:
                data += bytearray("%30s%10i%9i\n" % (student,0,0))
            else: print "cancelled"
        else:
            break
    datafile = open(directory_name + "scores.txt",'w')
    datafile.write(data)
    datafile.close()

while True:
    print """\
Welcome to Simple-Maths Questions program
Please type one of the following:
Play | Leaderboard | Exit"""
    command = raw_input()
    command = command.upper()
    if command in "PLAY":
        play()
    elif command in "LEADERBOARD":
        leaderboard()
    elif command in "EXIT":
        break
    elif command in "ADD NAME":
        add_student()
    else:
        print "unknown command"

Note: I haven't exactly exhaustively bug tested this, so please do a bit of testing yourself to make sure this works.
NOTE 2: Amended cmp function; .sort behaved erratically with close floating pt. numbers.