Using Python's pickle to open and save a dictionary - python

In the final days of my intro comp sci class, we got to creating dictionaries. A homework program in our book asks us to create something that can look up, add, change, and delete a set of names and email addresses. It asks us to pickle the dictionary, but the kicker for me is that it stipulates that each time the program starts, it should retrieve the dictionary from the file and unpickle it. I don't know if I coded myself into a corner, but I can't figure out how to do this with what I've done so far.
My code:
import mMyUtils
import pickle
LOOK_UP = 1
ADD = 2
CHANGE = 3
DELETE = 4
QUIT = 5
def main():
emails = {}
choice = 0
while choice != QUIT:
choice = getMenuChoice()
if choice == LOOK_UP:
lookUp(emails)
elif choice == ADD:
add(emails)
elif choice == CHANGE:
change(emails)
elif choice == DELETE:
delete(emails)
else:
exit
def getMenuChoice():
print()
print('Name and Email Address Catalog')
print('------------------------------')
print('1. Look up an email address')
print('2. Add a new email address')
print('3. Change an email address')
print('4. Delete an email address')
print('5. Quit the program')
print()
choice = int(input('Enter the choice: '))
while choice < LOOK_UP or choice > QUIT:
choice = int(input('Enter a valid choice: '))
return choice
def lookUp(emails):
name = input('Enter a name: ')
print(emails.get(name, 'Not found.'))
def add(emails):
name = input('Enter a name: ')
address = input('Enter an email address: ')
if name not in emails:
emails[name] = address
pickle.dump(emails, open("emails.dat", "wb"))
else:
print('That entry already exists.')
def change(emails):
name = input('Enter a name: ')
if name in emails:
address = input('Enter the new address: ')
emails[name] = address
pickle.dump(emails, open("emails.dat", "wb"))
else:
print('That name is not found.')
def delete(emails):
name = input('Enter a name: ')
if name in emails:
del emails[name]
else:
print('That name is not found.')
main()
I know I should set my emails variable to be some form of pickle.load, but I can't figure it out for the life of me. mMyUtils is a library I made for try/except logic, I'll put that in once I get the new stuff working.

If you're saving the dictionary like so:
pickle.dump(emails, open('emails.dat', 'wb'))
The following will load it back:
emails = pickle.load(open('emails.dat', 'rb'))

You must load the file and unpickle the data before you can access it, change lookUp() to this:
def lookUp(emails):
with open("emails.dat", "rb") as fo:
emails = pickle.load(fo)
name = input('Enter a name: ')
print(emails.get(name, 'Not found.'))

Consider yourself using ast.literal_eval instead of pickle: http://docs.python.org/2/library/ast.html#ast.literal_eval
>>>import ast
>>> print mydict
{'bob': 1, 'danny': 3, 'alan': 2, 'carl': 40}
>>> string="{'bob': 1, 'danny': 3, 'alan': 2, 'carl': 40}"
>>> type(string)
<type 'str'>
>>> type( ast.literal_eval(string) )
<type 'dict'>
To save/read dict from file, you can do it like with normal string.

The problem was, and I guess I didn't emphasis it enough, was what I was supposed to do if the dictionary didn't exist in the first place. The design doc states that you should load the dictionary every time you run the program. Well if you're running the program for the first time, you don't have a dictionary to load, leading to an error. I got around this by basically doing the function twice using try/except.
My code:
import mMyUtils
import pickle
import dictionaryGenerator
LOOK_UP = 1
ADD = 2
CHANGE = 3
DELETE = 4
QUIT = 5
def main():
hasError = False
try:
emails = pickle.load(open('emails.dat', 'rb'))
choice = 0
while choice != QUIT:
choice = getMenuChoice()
if choice == LOOK_UP:
lookUp(emails)
elif choice == ADD:
add(emails)
elif choice == CHANGE:
change(emails)
elif choice == DELETE:
delete(emails)
else:
print("Good-bye!")
exit
except Exception as err:
hasError = True
mMyUtils.printError("Error: no such file",err)
mMyUtils.writeToErrorLog()
finally:
if hasError:
emails = {}
choice = 0
while choice != QUIT:
choice = getMenuChoice()
if choice == LOOK_UP:
lookUp(emails)
elif choice == ADD:
add(emails)
elif choice == CHANGE:
change(emails)
elif choice == DELETE:
delete(emails)
else:
print("Good-bye!")
exit
def getMenuChoice():
print()
print('Name and Email Address Catalog')
print('------------------------------')
print('1. Look up an email address')
print('2. Add a new email address')
print('3. Change an email address')
print('4. Delete an email address')
print('5. Quit the program')
print()
choice = int(input('Enter the choice: '))
while choice < LOOK_UP or choice > QUIT:
choice = int(input('Enter a valid choice: '))
return choice
def lookUp(emails):
name = input('Enter a name: ')
print(emails.get(name, 'Not found.'))
def add(emails):
name = input('Enter a name: ')
address = input('Enter an email address: ')
if name not in emails:
emails[name] = address
with open("emails.dat", "wb") as infile:
pickle.dump(emails, infile)
else:
print('That entry already exists.')
def change(emails):
name = input('Enter a name: ')
if name in emails:
address = input('Enter the new address: ')
emails[name] = address
with open("emails.dat", "wb") as infile:
pickle.dump(emails, infile)
else:
print('That name is not found.')
def delete(emails):
name = input('Enter a name: ')
if name in emails:
del emails[name]
else:
print('That name is not found.')
main()

Related

How to have input in Python only take in string and not number or anything else only letters

I am a beginner in Python so kindly do not use complex or advanced code.
contact = {}
def display_contact():
for name, number in sorted((k,v) for k, v in contact.items()):
print(f'Name: {name}, Number: {number}')
#def display_contact():
# print("Name\t\tContact Number")
# for key in contact:
# print("{}\t\t{}".format(key,contact.get(key)))
while True:
choice = int(input(" 1. Add new contact \n 2. Search contact \n 3. Display contact\n 4. Edit contact \n 5. Delete contact \n 6. Print \n 7. Exit \n Enter "))
#I have already tried
if choice == 1:
while True:
try:
name = str(input("Enter the contact name "))
if name != str:
except ValueError:
continue
else:
break
while True:
try:
phone = int(input("Enter number "))
except ValueError:
print("Sorry you can only enter a phone number")
continue
else:
break
contact[name] = phone
elif choice == 2:
search_name = input("Enter contact name ")
if search_name in contact:
print(search_name, "'s contact number is ", contact[search_name])
else:
print("Name is not found in contact book")
elif choice == 3:
if not contact:
print("Empty Phonebook")
else:
display_contact()
elif choice == 4:
edit_contact = input("Enter the contact to be edited ")
if edit_contact in contact:
phone = input("Enter number")
contact[edit_contact]=phone
print("Contact Updated")
display_contact()
else:
print("Name is not found in contact book")
elif choice == 5:
del_contact = input("Enter the contact to be deleted ")
if del_contact in contact:
confirm = input("Do you want to delete this contact Yes or No? ")
if confirm == 'Yes' or confirm == 'yes':
contact.pop(del_contact)
display_contact
else:
print("Name is not found in phone book")
elif choice == 6:
sort_contact = input("Enter yes to print your contact")
if sort_contact in contact:
confirm = input("Do you want to print your contact Yes or No? ")
if confirm == 'Yes' or confirm == 'yes':
strs = [display_contact]
print(sorted(strs))
else:
print("Phone book is printed.")
else:
break
I tried but keep getting errors and I can't fiugre out how to make it only take string or letter as input and not numbers.
if choice == 1:
while True:
try:
name = str(input("Enter the contact name "))
if name != str:
except ValueError:
continue
else:
break
it is not working my code still accepts the ans in integer and string.
I am a beginner so I might have made a lot of mistakes. Your patience would be appreciated.
You can use a regex with re.fullmatch:
import re
while True:
name = input("Enter the contact name ")
if re.fullmatch(r'[a-zA-Z]+', name):
break
Or use the case-insensitive flag: re.fullmatch(r'[a-z]+', name, flags=re.I):
As you noted that you are a beginner, I'm adding this piece of code
as a "custom-made" validation, just so you can check how you would do something like this by your own .
Note: #mozway gave a MUCH BETTER solution, that is super clean, and I recommend it over this one.
def valid_input(input: str):
# Check if any char is a number
for char in input:
if char.isdigit():
print('Numbers are not allowed!')
return False
return True
while True:
name = input("Enter data:")
if valid_input(name):
break
I found this answer from another website:
extracted_letters = " ".join(re.findall("[a-zA-Z]+", numlettersstring))
First, import re to use the re function.
Then let's say that numlettersstring is the string you want only the letters from.
This piece of code will extract the letters from numlettersstring and output it in the extracted_letters variable.

How do I print out a set of information at once in python?

I'm a python beginner I tried making a contact book program but this is the problem, I
want to add search-like feature so after I add a contact name, phone number, email and store
it to another file(contact.txt) I want to access it and print it via search.
example:
Name: Johan
Phone: 036902480157
Email: Johan#Email.com
I want to access all the information regarding Johan just by typing his contact name or his phone number, how I can do that?
note: I want to print the name, phone number, and email in each different line
Thanks in advance
my code
import os
def head():
print("")
print("========================")
print(" Contact Book ")
print("========================")
def restart():
response = input("\nOpen menu again? (yes/no): ").lower()
if response == "yes":
task()
else:
print("\nSee You next time!")
def task():
head()
done = False
print('''1. Add Contact
2. Search
3. View Contact List
4. Delete All Contact
5. Exit''')
while not done:
task = input("\nWhat do You want to do? (1-5):")
if task == "1":
print("\nAdding a new contact!")
with open('contact.txt', 'a') as f:
name = input("Name: ")
phone = input("Phone Number: ")
if not phone.isnumeric():
while not phone.isnumeric():
print("Invalid input, please enter only a number!")
phone = input("Phone Number: ")
email = input("Enter an email: ")
f.writelines(('\n',('=' * 15),'\nName: ',name,
'\nPhone: ',phone,'\nEmail: ',email,'\n',('=' * 15)))
print("\nContact is saved!")
done = True
restart()
elif task == "2":
with open('contact.txt', 'r') as f:
search = input("\nSearch: ")
for i in f:
if search in i:
print(i)
else:
print("\nNo info was found!")
done = True
restart()
elif task == "3":
if os.path.getsize('contact.txt') == 0:
print("\nNo contact info available!")
else:
with open('contact.txt', 'r') as f:
print("\nAll Contact Info")
for i in f:
print(i,end="")
done = True
restart()
elif task == "4":
with open('contact.txt', 'w') as f:
print("\nSuccesfully deleted all contact info!")
done = True
restart()
elif task == "5":
print("See You next time!")
break
else:
print("Invalid input please enter a single number from 1 to 5")
restart()
task()
Adding a contact and then searching for this contact prints:
Adding a new contact!
Name: mrd
Phone Number: 99
Enter an email: the#ff.com
Contact is saved!
...
What do You want to do? (1-5):2
Search: mrd
Name: mrd
No info was found!
which is inaccurate as you just fount the name. What you want to do is save all the contact info in the same line in the contacts.txt so when you search for a number or a name it will give you back that line and then you can print it as you want.
Alternatively you could hold an in memory dictionary that you persist on exit in a json as suggested and you load when you start your program
In answer to the comment
if task == "1":
print("\nAdding a new contact!")
# TODO make sure no commas in the input!
name = input("Name: ")
phone = input("Phone Number: ")
while not phone.isnumeric():
print("Invalid input, please enter only a number!")
phone = input("Phone Number: ")
email = input("Enter an email: ")
with open('contact.txt', 'a') as f:
f.write(','.join([name, phone, email]) + '\n')
print("\nContact is saved!")
done = True
restart()
elif task == "2":
search = input("\nSearch: ")
with open('contact.txt', 'r') as f:
for i in f:
if search in i:
for caption, data in zip(['Name:', 'Phone:', 'Email:'],
i.split(',')):
print(caption, data)
break # contact was found don't go to the else!
else:
print("\nNo info was found!")
done = True
restart()

i need multiple input to run main function phonebook python

I am having trouble writing a program to repeat input part. for instance
input 1 ___run add_contact()
again ask for input
input 4____run disp_contact()
...
...
I've never written a long code! :\
I'm totally begginer! and learning a bit of Python in my spare time
my mentor said you should define several functions and put them in a main function which get input.
so If anyone can tell me why I get stuck like this I would appreciate it.
contact={}
print(''' phone book
1. add contact
2.delete contact
3.search contact
4.display all
5.Quit''')
def add_contact():
name=input('enter the name: ')
number=input('enter the number: ')
contact[name]=number
print(name, 'added to phone book!')
def del_contact():
name=input('enter the name: ')
while name not in contact:
print("not found! try again" )
name=input('enter again: ')
else:
print(name,' deleted')
del contact[name]
name=False
def search_contact():
name=input('enter the name: ')
while name not in contact:
print('not found!')
name=input('enter again: ')
else:
print(name, 'number is :', contact[name])
def disp_contact():
if len(contact)>0:
print('phone book contacts are: ')
for i in contact:
print(i, end=' ')
else:
print('phone book is empty!')
def main_def(num):
if num==1:
add_contact()
elif num==2:
del_contact()
elif num==3:
search_contact()
elif num==4:
disp_contact()
elif num==5:
print('bye bye')
x=int(input(' enter a number: '))
main_def(x)
You may wrap the main_def in a while True, and use exit(O) to quit properly when 5 is given
def main_def(num):
if num == 1:
add_contact()
elif num == 2:
del_contact()
elif num == 3:
search_contact()
elif num == 4:
disp_contact()
elif num == 5:
exit(0)
while True:
x = int(input(' enter a number: '))
main_def(x)
Note
For del_contact and search_contact, you don't need the else just put after like this
def del_contact():
name = input('enter the name: ')
while name not in contact:
print("not found! try again")
name = input('enter again: ')
print(name, ' deleted')
del contact[name]

How can I open a file in Python to a dictionary

I have a file with a bunch of names and emails.
They are written as follows:
name
email
name
email
I cant figure out how to open the file and read line by line to where it pairs "name to email" in my dictionary
I got the code to work when I manually type in the names/emails into the dictionary but I need to pull it from the file.
LOOK_UP=1
ADD= 2
CHANGE= 3
DELETE=4
QUIT=5
def main():
emails={}
with open('phonebook.in') as f:
for line in f:
(name, email)=line.split
emails[name]=email
choice=0
while choice !=QUIT:
choice= get_menu_choice()
if choice == LOOK_UP:
look_up(emails)
elif choice == ADD:
add(emails)
elif choice == CHANGE:
change(emails)
elif choice == DELETE:
delete(emails)
def get_menu_choice():
print('Enter 1 to look up an email address')
print('Enter 2 to add an email address')
print('Enter 3 to change an email address')
print('Enter 4 to delete an email address')
print('Enter 5 to Quit the program')
print()
choice= int(input('Enter your choice: '))
while choice <LOOK_UP or choice >QUIT:
choice= int(input('Enter a valid choice'))
return choice
def look_up(emails):
name= str(input('Enter a name: '))
value=(emails.get(name, 'Not found.'))
print(value)
print()
def add(emails):
name= str(input('Enter a name: '))
emailsaddy= input(' Enter a email address: ')
if name not in emails:
emails[name]= emailsaddy
print()
else:
print('That contact already exists')
print()
def change(emails):
name=str(input ('Enter a name: '))
if name in emails:
emailsaddy= str(input(' Enter a new email: '))
emails[name]= emailsaddy
else:
print('That contact does not exist')
def delete(emails):
name=str(input ('Enter a name: '))
if name in emails:
del emails[name]
else:
print('That contact is not found')
main()
Do something like this, every name line goes in if statement, and every email line goes in else and add to directory.
emails = {}
i = 0
with open('phonebook.in') as f:
for line in f:
if i == 0:
name = line
i = 1
else:
email = line
emails[name] = email
i = 0
with open('phonebook.in') as f:
# convert file into list
pb = f.readlines()
# pair off elements into (name, email) tuples, and construct a dict from them
emails = dict(zip(pb[0::2], pb[1::2]))
See this answer for an explanation, in case that idiom is hard to understand

Limit the amount of inputs in a Python list

I want to set a limit to which the user can input names. This is where I got to and got stuck. How would I set a limit of 10 to the names the user can input into the list and restrict them from entering anymore?
names = []
print ('1 = Add Name ')
print ('2 = Display List ')
print ('3 = Quit ')
while True:
option = input('What would you like to do: ')
if option == '1':
name= input('Enter name: ')
names.append(name)
you can do :
if option == '1':
names = [input('Enter name:') for _ in range(10)]
I hope that following script can help you:
# libraries
import sys
# list variable to store name
names = []
# limits to save name
limit = 10
# function to display menu
def menu():
print("Enter 1 to add Name")
print("Enter 2 to show list")
print("Enter 3 to quit")
choice = int(raw_input("Enter your choice : "))
return choice
# running for infinite times till user quits
while(True):
choice = menu()
if(choice == 1):
name = raw_input("Enter name to add in list : ")
if(len(names) > 10):
print("You cannot enter more names")
else:
names.append(name)
print(name + " - Name saved successfully.")
if(choice == 2):
print("List of names : ")
print(names)
if(choice == 3):
sys.exit()

Categories

Resources