这个菜单驱动程序在二进制文件(姓名、卷、年龄、标记)中输入学生记录并执行以下操作的错误是什么
What is the error in this menu driven program to input records of students in a binary file (name,roll,age,marks) and perform the following operations
import pickle
def main():
while True:
print(''' 1. Create Binary File.
2. Display Binary File.
3. Search for a given roll number.
4. Input roll number and mark, Update mark of the student.
5. Delete a record for a given roll number
6. Display the details of the students getting average marks more than 80.
7. Append new records at the end of file.
8. Exit''')
choice=int(input('choose a command (1..8): '))
if choice==1:
f=open('student.dat','wb')
entries=int(input('How many entries?: '))
for entry in range(entries):
name=str(input('enter a name: '))
rollno=int(input('enter a roll no: '))
age=int(input('Students age: '))
avg_marks=int(input('avg mark= '))
t=[name,rollno,age,avg_marks]
pickle.dump(t,f)
f.close()
print('File created')
elif choice==2:
f=open('student.dat','rb')
try:
while True:
content=pickle.load(f)
print(content)
except:
f.close()
elif choice==3:
f=open('student.dat','rb')
roll_find=int(input('roll no of the student to find: '))
while True:
content=pickle.load(f)
if content[1]==roll_find:
print(content)
break
f.close()
elif choice==4:
roll_find=int(input('roll to find'))
new_marks=int(input('new_marks'))
rows=[]
f=open('student.dat','rb')
try:
while True:
content=pickle.load(f)
rows.append(content)
except:
pass
for row in rows:
if row[1]==roll_find:
row[3]=new_marks
print('row found and updated')
f.close()
f=open('studen.dat','wb')
for row in rows:
pickle.dump(row,f)
f.close()
elif choice==5:
f=open('student.dat','rb')
roll_find=int(input('roll no of the student: '))
while True:
content=pickle.load(f)
if content[1]==roll_find:
del content[:]
print('roll no found and row deleted: ')
break
f.close()
除了更新和删除卷号外,一切正常。
我能够输入新的详细信息,但由于某种原因它不会覆盖之前写的内容。
检查第 4 个选项和第 5 个选项是否有错误代码。
您的问题是您正在读取内容但没有再次存储它们。但是这段代码要求一些辅助功能,以便一切都保持干净。让我们开始制作一些辅助函数并同时解决问题。
我们要求用户提供几个整数,所以让我们创建一个函数来处理这个问题。它将 return 一个特殊数字(默认为 0),以防我们无法将用户提供的内容转换为整数。
def input_integer(request: str, *, error: int = 0) -> int:
try:
return int(input(request))
except ValueError: # If we can't convert to integer return error
return error
注意:如果您不习惯类型注释,它们意味着 input_integer
函数需要一个字符串参数(这是请求整数的消息)和一个允许配置的关键字整数参数which integer to return as an error, defaulting to 0. 函数 returns 是一个整数。通过创建此注释,reader 将更好地理解函数的作用,IDE 将检测到一些类型不匹配错误,但不会在运行时对其进行评估。
好的,我们要打印一个菜单,让我们也为它做一个函数。实际上,我们将创建一个 return 函数。 outter 函数将自己构建菜单,returned 函数将打印它并请求用户输入。
def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# Number of options
options_number = len(options)
# Menu text
menu_text_lines = ["MENU:"]
for i, option in enumerate(options):
menu_text_lines.append(f"\t{i+1}. {option}")
menu_text = "\n".join(menu_text_lines)
# Input request text
input_request += f" (1..{options_number}): "
# Create the function that will be called to print the menu
def menu_function() -> int:
# Print the menu text we have previously built
print(menu_text)
# Get the input from the user until he gives a valid one
choice = input_integer(input_request)
while not(0 < choice <= options_number):
print(f"It must be a number between 1 and {options_number}.")
choice = input_integer(input_request)
# Return the choice of the user
return choice
return menu_function
如您所见,函数可以在其他块内定义,并且可以像任何其他对象一样 returned。该函数接受一个字符串列表,这些字符串是选项和一个附加字符串以请求用户输入。它将构建添加数字的完整消息并准备我们稍后将调用的函数。在这种情况下,menu_factory
函数将这样调用:
menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)
现在,menu()
将打印菜单,请求用户选择,并且 return 验证后选择是正确范围内的正确数字。
接下来我们将有一个 class 来存储每个学生的信息而不是列表。它将具有 4 个属性(姓名、卷号、年龄和标记)。构造函数 (__init__
) 只会保存它们。我还添加了一个 __repr__
告诉 python 如何 print
学生对象。 class 定义顶部的 __slots__
是内存优化。通过设置 __slots__
我们告诉 class 它将拥有哪些确切的属性,而不必将它们存储为通用字典。如果您删除此行,它仍然会完全相同,但您加载的每个学生都会消耗更多的 RAM。
class Student:
__slots__ = 'name', 'roll_no', 'age', 'mark'
def __init__(self, name: str, roll_no: int, age: int, mark: int) -> None:
self.name = name
self.roll_no = roll_no
self.age = age
self.mark = mark
def __repr__(self) -> str:
return f"Student<name={self.name}, roll_no={self.roll_no}, " \
f"age={self.age}, mark={self.mark}>"
我们已经差不多完成了,但还有一件事我们还要做很多次,即读取和写入文件。让我们为此创建一些辅助函数。 read_file
函数将创建 list
个 Stundet
。第一个 try: ... except FileNotFoundError: pass
块检测是否找不到文件(返回 Student
的空列表)。 with open(...) as f: ...
如果是比事后调用 f.close()
更好的方法。 Python 本身将在您离开 with
块时关闭文件,无论是由于异常还是任何其他原因。所以基本上我们肯定知道文件无论如何都会被关闭。里面的try: ... except EOFError: break
是检测我们什么时候结束读取文件,然后跳出无限while True: ...
循环。
def read_file(path: str) -> List[Student]:
content = []
try:
with open(path, 'rb') as f:
while True:
try:
content.append(pickle.load(f))
except EOFError: # Break the loop when reached end of the file
break
except FileNotFoundError: # Don't raise if the file doesn't exist
pass
return content
写入函数很简单,打开文件,写入内容,大功告成。追加也是如此。
def write_file(path: str, content: List[Student]) -> None:
with open(path, 'wb') as f:
for row in content:
pickle.dump(row, f)
def append_file(path: str, content: List[Student]) -> None:
with open(path, 'ab') as f:
for row in content:
pickle.dump(row, f)
所以现在我们有一个 input_integer
函数可以从用户那里读取整数,一个 menu_factory
函数可以构建菜单,一个 Student
class 可以存储每个学生的信息,以及 read_file
、write_file
和 append_file
函数。我们可以开始实现我们的逻辑了。我将创建一个函数字典,其中键将是整数选择,值是我们将调用以实现该选项的函数。现在我们已经设置了这些辅助方法,您将看到 choice_X
函数将变得非常简单。
import pickle
from typing import Callable, List
FILENAME = 'student.bat'
def input_integer(request: str, *, error: int = 0) -> int:
# ...
def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# ...
class Student:
# ...
def read_file(path: str) -> List[Student]:
# ...
def write_file(path: str, content: List[Student]) -> None:
# ...
def append_file(path: str, content: List[Student]) -> None:
# ...
if __name__ == '__main__' :
# Create the menu function from the factory
menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)
def choice_1() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
write_file(FILENAME, students)
def choice_2() -> None:
print(read_file(FILENAME))
def choice_3() -> None:
roll_no = input_integer("Roll number of the student to find: ")
for student in read_file(FILENAME):
if student.roll_no == roll_no:
print(student)
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
def choice_4() -> None:
roll_no = input_integer("Roll number of the student to update: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return
students[i].mark = input_integer("New average mark: ")
write_file(FILENAME, students)
def choice_5() -> None:
roll_no = input_integer("Roll number of the student to delete: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return
del students[i]
write_file(FILENAME, students)
def choice_6() -> None:
for i, student in enumerate(read_file(FILENAME)):
if student.mark >= 80:
print(student)
def choice_7() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
append_file(FILENAME, students)
menu_callbacks = {
1: choice_1,
2: choice_2,
3: choice_3,
4: choice_4,
5: choice_5,
6: choice_6,
7: choice_7,
}
# Option number 8 is Exit
while (choice := menu()) != 8:
print()
try:
callback = menu_callbacks[choice]
except KeyError:
print("NOT IMPLEMENTED YET")
else:
callback()
print("\n")
import pickle
def main():
while True:
print(''' 1. Create Binary File.
2. Display Binary File.
3. Search for a given roll number.
4. Input roll number and mark, Update mark of the student.
5. Delete a record for a given roll number
6. Display the details of the students getting average marks more than 80.
7. Append new records at the end of file.
8. Exit''')
choice=int(input('choose a command (1..8): '))
if choice==1:
f=open('student.dat','wb')
entries=int(input('How many entries?: '))
for entry in range(entries):
name=str(input('enter a name: '))
rollno=int(input('enter a roll no: '))
age=int(input('Students age: '))
avg_marks=int(input('avg mark= '))
t=[name,rollno,age,avg_marks]
pickle.dump(t,f)
f.close()
print('File created')
elif choice==2:
f=open('student.dat','rb')
try:
while True:
content=pickle.load(f)
print(content)
except:
f.close()
elif choice==3:
f=open('student.dat','rb')
roll_find=int(input('roll no of the student to find: '))
while True:
content=pickle.load(f)
if content[1]==roll_find:
print(content)
break
f.close()
elif choice==4:
roll_find=int(input('roll to find'))
new_marks=int(input('new_marks'))
rows=[]
f=open('student.dat','rb')
try:
while True:
content=pickle.load(f)
rows.append(content)
except:
pass
for row in rows:
if row[1]==roll_find:
row[3]=new_marks
print('row found and updated')
f.close()
f=open('studen.dat','wb')
for row in rows:
pickle.dump(row,f)
f.close()
elif choice==5:
f=open('student.dat','rb')
roll_find=int(input('roll no of the student: '))
while True:
content=pickle.load(f)
if content[1]==roll_find:
del content[:]
print('roll no found and row deleted: ')
break
f.close()
除了更新和删除卷号外,一切正常。 我能够输入新的详细信息,但由于某种原因它不会覆盖之前写的内容。 检查第 4 个选项和第 5 个选项是否有错误代码。
您的问题是您正在读取内容但没有再次存储它们。但是这段代码要求一些辅助功能,以便一切都保持干净。让我们开始制作一些辅助函数并同时解决问题。
我们要求用户提供几个整数,所以让我们创建一个函数来处理这个问题。它将 return 一个特殊数字(默认为 0),以防我们无法将用户提供的内容转换为整数。
def input_integer(request: str, *, error: int = 0) -> int:
try:
return int(input(request))
except ValueError: # If we can't convert to integer return error
return error
注意:如果您不习惯类型注释,它们意味着 input_integer
函数需要一个字符串参数(这是请求整数的消息)和一个允许配置的关键字整数参数which integer to return as an error, defaulting to 0. 函数 returns 是一个整数。通过创建此注释,reader 将更好地理解函数的作用,IDE 将检测到一些类型不匹配错误,但不会在运行时对其进行评估。
好的,我们要打印一个菜单,让我们也为它做一个函数。实际上,我们将创建一个 return 函数。 outter 函数将自己构建菜单,returned 函数将打印它并请求用户输入。
def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# Number of options
options_number = len(options)
# Menu text
menu_text_lines = ["MENU:"]
for i, option in enumerate(options):
menu_text_lines.append(f"\t{i+1}. {option}")
menu_text = "\n".join(menu_text_lines)
# Input request text
input_request += f" (1..{options_number}): "
# Create the function that will be called to print the menu
def menu_function() -> int:
# Print the menu text we have previously built
print(menu_text)
# Get the input from the user until he gives a valid one
choice = input_integer(input_request)
while not(0 < choice <= options_number):
print(f"It must be a number between 1 and {options_number}.")
choice = input_integer(input_request)
# Return the choice of the user
return choice
return menu_function
如您所见,函数可以在其他块内定义,并且可以像任何其他对象一样 returned。该函数接受一个字符串列表,这些字符串是选项和一个附加字符串以请求用户输入。它将构建添加数字的完整消息并准备我们稍后将调用的函数。在这种情况下,menu_factory
函数将这样调用:
menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)
现在,menu()
将打印菜单,请求用户选择,并且 return 验证后选择是正确范围内的正确数字。
接下来我们将有一个 class 来存储每个学生的信息而不是列表。它将具有 4 个属性(姓名、卷号、年龄和标记)。构造函数 (__init__
) 只会保存它们。我还添加了一个 __repr__
告诉 python 如何 print
学生对象。 class 定义顶部的 __slots__
是内存优化。通过设置 __slots__
我们告诉 class 它将拥有哪些确切的属性,而不必将它们存储为通用字典。如果您删除此行,它仍然会完全相同,但您加载的每个学生都会消耗更多的 RAM。
class Student:
__slots__ = 'name', 'roll_no', 'age', 'mark'
def __init__(self, name: str, roll_no: int, age: int, mark: int) -> None:
self.name = name
self.roll_no = roll_no
self.age = age
self.mark = mark
def __repr__(self) -> str:
return f"Student<name={self.name}, roll_no={self.roll_no}, " \
f"age={self.age}, mark={self.mark}>"
我们已经差不多完成了,但还有一件事我们还要做很多次,即读取和写入文件。让我们为此创建一些辅助函数。 read_file
函数将创建 list
个 Stundet
。第一个 try: ... except FileNotFoundError: pass
块检测是否找不到文件(返回 Student
的空列表)。 with open(...) as f: ...
如果是比事后调用 f.close()
更好的方法。 Python 本身将在您离开 with
块时关闭文件,无论是由于异常还是任何其他原因。所以基本上我们肯定知道文件无论如何都会被关闭。里面的try: ... except EOFError: break
是检测我们什么时候结束读取文件,然后跳出无限while True: ...
循环。
def read_file(path: str) -> List[Student]:
content = []
try:
with open(path, 'rb') as f:
while True:
try:
content.append(pickle.load(f))
except EOFError: # Break the loop when reached end of the file
break
except FileNotFoundError: # Don't raise if the file doesn't exist
pass
return content
写入函数很简单,打开文件,写入内容,大功告成。追加也是如此。
def write_file(path: str, content: List[Student]) -> None:
with open(path, 'wb') as f:
for row in content:
pickle.dump(row, f)
def append_file(path: str, content: List[Student]) -> None:
with open(path, 'ab') as f:
for row in content:
pickle.dump(row, f)
所以现在我们有一个 input_integer
函数可以从用户那里读取整数,一个 menu_factory
函数可以构建菜单,一个 Student
class 可以存储每个学生的信息,以及 read_file
、write_file
和 append_file
函数。我们可以开始实现我们的逻辑了。我将创建一个函数字典,其中键将是整数选择,值是我们将调用以实现该选项的函数。现在我们已经设置了这些辅助方法,您将看到 choice_X
函数将变得非常简单。
import pickle
from typing import Callable, List
FILENAME = 'student.bat'
def input_integer(request: str, *, error: int = 0) -> int:
# ...
def menu_factory(options: List[str], input_request: str) -> Callable[[], int]:
# ...
class Student:
# ...
def read_file(path: str) -> List[Student]:
# ...
def write_file(path: str, content: List[Student]) -> None:
# ...
def append_file(path: str, content: List[Student]) -> None:
# ...
if __name__ == '__main__' :
# Create the menu function from the factory
menu = menu_factory(
[
"Create Binary File.",
"Display Binary File.",
"Search for a given roll number.",
"Input roll number and mark, Update mark of the student.",
"Delete a record for a given roll number.",
"Display the details of the students getting average marks "
"more than 80.",
"Append new records at the end of file.",
"Exit",
],
"Choose a command"
)
def choice_1() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
write_file(FILENAME, students)
def choice_2() -> None:
print(read_file(FILENAME))
def choice_3() -> None:
roll_no = input_integer("Roll number of the student to find: ")
for student in read_file(FILENAME):
if student.roll_no == roll_no:
print(student)
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
def choice_4() -> None:
roll_no = input_integer("Roll number of the student to update: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return
students[i].mark = input_integer("New average mark: ")
write_file(FILENAME, students)
def choice_5() -> None:
roll_no = input_integer("Roll number of the student to delete: ")
students = read_file(FILENAME)
for i, student in enumerate(students):
if student.roll_no == roll_no:
break
else: # This will only be executed if no break was found
print(f"Roll number {roll_no} not found in data file.")
return
del students[i]
write_file(FILENAME, students)
def choice_6() -> None:
for i, student in enumerate(read_file(FILENAME)):
if student.mark >= 80:
print(student)
def choice_7() -> None:
students = []
for i in range(1, input_integer("How many entries? ") + 1):
print(f"Entry number {i}:")
students.append(Student(
input("\tName: "),
input_integer("\tRoll number: "),
input_integer("\tStudent age: "),
input_integer("\tAverage mark: "),
))
append_file(FILENAME, students)
menu_callbacks = {
1: choice_1,
2: choice_2,
3: choice_3,
4: choice_4,
5: choice_5,
6: choice_6,
7: choice_7,
}
# Option number 8 is Exit
while (choice := menu()) != 8:
print()
try:
callback = menu_callbacks[choice]
except KeyError:
print("NOT IMPLEMENTED YET")
else:
callback()
print("\n")