简体   繁体   中英

How to remove an object stored in a Pickle file with Python

I am working on a database program that stores objects in a pickle file. The objects have three attributes: Name, Grade, and Average. I have been able to save each Student object to a pickle file, and I can read the file back and display it's contents. However, I cannot figure out how to delete an object from the file using an index number. I want the user to be able to type in a number, and then delete that numbered object (so if I type in 2, the second object is deleted.) Right now my code is able to delete an item from a pickle list, but I cannot get it to work with an object. When I try to delete a student, I get the following error: TypeError: 'Student' object does not support item deletion. Does anyone know how I could delete an object from my pickle file?

My code is below:

import pickle

class Student():
    def __init__(self,nam,grd,avg):
        self.name = nam
        self.grade = grd
        self.average = avg

    def get_details(self):
        print(self.name, self.grade, self.average)

    def create_item():
        new_student = Student(input("Enter name: "),input("Enter grade: "), input("Enter average: "))
        save_object(new_student, 'student_data.pkl')

    def clear_database():
        file = open('student_data.pkl', 'w')
        file.close()

def save_object(obj, filename):
    with open(filename, 'ab') as output:
        pickle.dump(obj, output, pickle.HIGHEST_PROTOCOL)

def unpickle_database(filename):
    with open(filename, 'rb') as f:
        while True:
            try:
                yield pickle.load(f)
            except EOFError:
                break

def display_database():
    print("\nName:               Grade:              Average:            ")
    for student in unpickle_database('student_data.pkl'):
        property_list = [student.name, student.grade, student.average]
        print(''.join([v.ljust(20,' ') for v in property_list]))

def delete_student(student_to_delete):
    with open('student_data.pkl', 'rb') as f:
        db = pickle.load(f)
    try:
        del db[student_to_delete]
    except KeyError:
        print("{user} doesn't exist in db".format(user=user_to_delete))

while True:
    user_input = input("\nType \"Clear\" to clear the database. Type \"Add\" to add a student. Type \"Display\" to display the database contents. Type \"Quit\" to quit the program. Type \"Remove\" to remove a student.\n")
    if user_input == "Quit":
        break
    if user_input == "Clear":
        Student.clear_database()
        print("\nThe database has been cleared.")
    elif user_input == "Add":
        Student.create_item()
        display_database()
    elif user_input == "Display":
        display_database()
    elif user_input == "Remove":
        student_to_delete = input("Type the student number that you would like to delete: ")
        delete_student(student_to_delete)

You can't delete objects directly from the Pickle file. I mean, you could do that, but it'd require you to parse its structure to determine where individual objects' data begins and ends. That's tedious and not very rewarding.

What you can do, though, is read all of the pickled students as a list:

students = list(unpickle_database(filename))

Then, delete one of the students from the list with del students[index] and finally re-pickle all the remaining students using said list:

for student in students:
    save_object(student, filename)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM