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)