Home > Blockchain >  pickle.load() adds a None object at the end
pickle.load() adds a None object at the end

Time:04-19

Hi there, I'm learning Python and trying to create a command-line Address Book as a dictionary, which is saved to a file using pickle (that's the briefing).

I've coded the add_contact and browse_contact functions, and they both work well. I have added a few contacts (whose names are simply "Test One", "Test Two" ... "Test Ten") plus their emails and phone numbers to the Address Book.

However, when I code the search_contact and modify_contact functions, I'll need to load the file back into a dictionary using pickle.load().

The problem is, as each contact was added one by one to the Address Book, if I simply use the following code, it will only return the first object in the Address Book:

with open("addressbook.data", "rb") as f:
    loaded_contacts = pickle.load(f)
    print(loaded_contacts)

Output:

{'Test One': ('[email protected]', '39893849')}

That's because "Pickle serializes a single object at a time, and reads back a single object." Based on the solution suggested here, I've changed to the following code, so I can load back all the objects into a dictionary called loaded_contacts:

with open("addressbook.data", "rb") as f:
    while True:
        try:
            loaded_contacts = print(pickle.load(f))
        except EOFError:
            break

That seems to work, but the loaded dictionary from the file will have an extra None object at the end, as shown below once loaded_contacts is printed out:

{'Test One': ('[email protected]', '39893849')}
{'Test Two': ('[email protected]', '93294798374')}
.
.
.
{'Test Ten': ('[email protected]', '79854399')}
None

Consequently, when I try to search for a name like "Test One" and try to retrieve its value, I will get TypeError: 'NoneType' object is not subscriptable because there is a None object at the end.

Here's the code (it needs more work but you'll get the idea):

with open("addressbook.data", "rb") as f:
    while True:
        try:
            loaded_contacts = print(pickle.load(f))
        except EOFError:
            break

search_name = input("Please enter a name: ")
print(loaded_contacts[search_name])

Here's the error message after I enter a name:

TypeError                                 Traceback (most recent call last)
/var/.../x.py in <module>
     11 
     12 search_name = input("Please enter a name: ")
---> 13 print(loaded_contacts[search_name])
     14 

TypeError: 'NoneType' object is not subscriptable

Not sure what I did wrong, or why there's an extra None object at the end of the loaded dictionary (or how to remove it). I know I could use a list to store all the values as strings, but the briefing is to create a dictionary to hold all the values and use the dictionary built-in methods to add, delete and modify the contacts--and hence my question here.

Edited to update:

Answer to the question (thanks @JohnGordon and @ewong):

In loaded_contacts = print(pickle.load(f)), print() won’t return anything, so assigning a variable to print() will return Noun.

However, simply removing print() won’t fully work—it solves the ‘None’ problem, but loaded_contacts will only be assigned to value of the last iteration of pickle.load(f).

Here's how to iterate all the objects in pickle.load(f) (if they were initially added one-by-one) and then store all of them in a dictionary:

loaded_contacts = {} # create an empty dictionary

with open("addressbook.data", "rb") as f: # open the file
    while True: # looping pickle.load(f)
        try:
            # add each object to the dictionary
            loaded_contacts.update(pickle.load(f))
        except EOFError:
            break # stop looping at the end of the file

CodePudding user response:

loaded_contacts = print(pickle.load(f))

This is your problem. You're assigning loaded_contacts to the return value of print(), which doesn't return anything, so it returns None by default.

Do this instead:

loaded_contacts = pickle.load(f)
print(loaded_contacts)
  • Related