I am working through the chapter exercises in Tony Gaddis's "Starting Out With Python" 3rd edition from a class I have taken previously. I'm in chapter 9 and Exercise 8 requires me to write a program that pickles a dictionary (name:email) to a file when it closes and unpickles that file retaining the data when it is opened. I have read every word in that chapter and I still don't understand how you can do both in the same file. When you use the open function it creates a file which, in my understanding, is a new file with no data. I'm thinking it may be a sequencing issue, as in where to put the dump and load lines of code but that doesn't make sense either. Logic dictates you have to open the file before you can dump to it.
If the 'open' function creates a file object and associates it with a file and this function appears early in the code (as in def main), what keeps it from zeroing out the file each time that line is called?
This is not a homework assignment. I have completed that class. I am doing this for my own edification and would appreciate any explanation which would help me to understand it. I have included my attempt at the solution which is reflected in the code below and will keep gnawing at it until I find the solution. I just thought since the gene pool is deeper here I would save myself some time and frustration. Thank you very much to those that choose to reply and if I am lacking in any pertinent data that would help to clarify this issue, please let me know.
import pickle
#global constants for menu choices
ADDNEW = 1
LOOKUP = 2
CHANGE = 3
DELETE = 4
EXIT = 5
#create the main function
def main():
#open the previously saved file
friends_file = open('friends1.txt', 'rb')
#friends = pickle.load(friends_file)
end_of_file = False
while not end_of_file:
try:
friends = pickle.load(friends_file)
print(friends[name])
except EOFError:
end_of_file = True
friends_file.close()
#initialize variable for user's choice
choice = 0
while choice != EXIT:
choice = get_menu_choice() #get user's menu choice
#process the choice
if choice == LOOKUP:
lookup(friends)
elif choice == ADDNEW:
add(friends)
elif choice == CHANGE:
change(friends)
elif choice == DELETE:
delete(friends)
#menu choice function displays the menu and gets a validated choice from the user
def get_menu_choice():
print()
print('Friends and Their Email Addresses')
print('---------------------------------')
print('1. Add a new email')
print('2. Look up an email')
print('3. Change a email')
print('4. Delete a email')
print('5. Exit the program')
print()
#get the user's choice
choice = int(input('Enter your choice: '))
#validate the choice
while choice < ADDNEW or choice > EXIT:
choice = int(input('Enter a valid choice: '))
#return the user's choice
return choice
#the add function adds a new entry into the dictionary
def add(friends):
#open a file to write to
friends_file = open('friends1.txt', 'wb')
#loop to add data to dictionary
again = 'y'
while again.lower() == 'y':
#get a name and email
name = input('Enter a name: ')
email = input('Enter the email address: ')
#if the name does not exist add it
if name not in friends:
friends[name] = email
else:
print('That entry already exists')
print()
#add more names and emails
again = input('Enter another person? (y/n): ')
#save dictionary to a binary file
pickle.dump(friends, friends1.txt)
friends1.close()
#lookup function looks up a name in the dictionary
def lookup(friends):
#get a name to look up
name = input('Enter a name: ')
#look it up in the dictionary
print(friends.get(name, 'That name was not found.'))
#the change function changes an existing entry in the dictionary
def change(friends):
#get a name to look up
name = input('Enter a name: ')
if name in friends:
#get a new email
email = input('Enter the new email address: ')
#update the entry
friends[name] = email
else:
print('That name is not found.')
#delete an entry from the dictionary
def delete(friends):
#get a name to look up
name = input('Enter a name: ')
#if the name is found delete the entry
if name in friends:
del [name]
else:
print('That name is not found.')
#call the main function
main()
If you open a file for reading with open("my_file","r") it will not change the file. The file must already exist. If you open a file for writing with open("my_file","w") it will create a new file, overwriting the old one if it exists. The first form (reading) is the default so you can omit the second "r" argument if you want. This is documented in the Python standard library docs.
Use open("myfile", 'r+') this allows both read and write functions. (at least in 2.7)
Related
I'm trying to get my code to check if a word is already in the document. However when choosing a variable (username) that happens to share the same letters going to the right as the preexisting one in the file, it thinks that the name is taken. For example, if abcdefg was in the file, if I was to right defg or fg or g, it would think the username was taken.
def register():
print("━━━━ACCOUNT CREATION━━━━")
username = input("Create Username: ")
with open("Login.txt", "r") as loginfile:
if (username+",") in loginfile.read():
print("Sorry, but that username is taken.")
choice = input("Try again with a new name? (Y/N)")
choice = choice.upper()
My case:
Say I had the name, Joe which is already in the file. If I tried to make a username that is just e, then it would think it is Joe, as it is looking for the e, next to a comma.
Anyway to fix this? Thanks!
This should work
with open('login.txt', 'r') as LoginFile:
# the split function splits a string to a list on mark
Data = LoginFile.read().split(" ,")
if username in Data:
# .....
if this isn't what you want try this built-in module :
https://docs.python.org/3/library/re.html
def register():
print("━━━━ACCOUNT CREATION━━━━")
# read the names from the file
with open('Login.txt', 'r') as f:
names = f.read().split(',')
username = input("Create Username: ")
for name in names:
# check if any names end with this name have been created
if name.endswith(username):
# found
print("Sorry, but that username is taken.")
# we want to keep ask the user to select if
# they enter something other than Y/N
while True:
# ask for the option
option = input("Try again with a new name? (Y/N) ")
# try again, we just rerun this function
if option == 'Y':
register()
# don't ask any more
break
elif option == 'N':
# exit if user chooses N
break
# if the user chooses something else, continue
# the loop and keep asking
# if no names end with username, goto else
break
else:
# name available, save it to the file
print("Name created successfully:", username)
new_names = names + [username]
with open('Login.txt', 'w') as f:
f.write(','.join(new_names))
I have tested it, please try and see if it works for you.
There's one last feature I want for my bank account system.
I want it to check if a username has already been saved to the text file database. If the username already exists, then it should tell the user that they can't have that name option. If not, then they would be able to use it.
The rest of my code works as it should, it's just the fcat that I can't append/update my text file properly and see if usernames already exist in the text file database.
import sys
users = {}
status = ""
# Functions ---------------------------------------------------------------------------------------------------------
# Select either account creation or login
def displayMenu():
global status
status = input("Are you a registered user? \n1 - Yes \n2 - No \nQ - Quit \n")
if status == '1':
oldUser()
elif status == '2':
newUser()
else:
print("Unknown input error, exiting . . . .")
sys.exit(0)
return status
# Account creation
def newUser():
global createLogin
createLogin = input("Create login name: ")
if createLogin in users: # check if login name exists
print ("\nLogin name already exists!\n")
else:
createPassw = input("Create password: ")
users[createLogin] = createPassw # add login and password
print("\nAccount created!\n")
#---- Storing the username in a txt file
file = open("accountfile.txt", "a")
file.write(createLogin)
file.write("\n")
file.close()
oldUser()
# Account login
def oldUser():
global login
login = input("Enter login name: ")
passw = input("Enter password: ")
# check if user exists and login matches password
if login in users and users[login] == passw:
file = open("accountfile.txt", "r")
for text in file: ######## This is where I'm trying to compare username duplicates
if text in file == createLogin:
print("Username already exists!")
print("\nLogin successful!\n")
Bank_Account()
else:
print("\nUser doesn't exist or wrong password!\n")
print("Restarting. Please enter details correctly . . . . .")
sys.exit(0)
class Bank_Account:
def __init__(self):
self.balance=0
response = ''
def deposit(self):
try:
amount=float(input("Enter amount to be Deposited: "))
except ValueError:
print("Enter digits only")
else:
self.balance += amount
print("\n Amount Deposited:",amount)
def withdraw(self):
try:
amount = float(input("Enter amount to be Withdrawn: "))
if self.balance>=amount:
self.balance-=amount
print("\n You Withdrew:", amount)
except ValueError:
print("Enter digits only")
s.withdraw()
else:
print("\n ")
def display(self):
print("\n Remaining Balance=",self.balance)
displayMenu()
s = Bank_Account()
# Calling functions with that class object
s.deposit()
s.withdraw()
s.display()
So it looks you are are writing the user input in the file accountfile.txt. So after a few users log in it might look something like:
$ cat accountfile.txt
mike
sarah
morgan
lee
The section of your code in question is here:
file = open("accountfile.txt", "r")
for text in file:
if text in file == createLogin:
print("Username already exists!")
This particular part is probably not doing what you think it's doing:
if text in file == createLogin
...
if text in file is returning either True or False.
...
So the line above is essentially saying
if False == createLogin
or
if True == createLogin
I believe what you want to do is check if a name is in accountfile.txt. The smallest change you could make to your code in order to achieve that would be
file = open("accountfile.txt", "r")
for text in file:
if text.strip() == createLogin: # .strip() will clean up the \n
print("Username already exists!")
This line:
if text in file == createLogin: is where you are making a mistake. The line is essentially saying:
"(if the text is in the file) compare the result of that check with the string createLogin".
i.e. if (True/False) == createLogin, which is always false because the True/False boolean primitives are never equal to any string (if it actually runs, i have not tested to see if an exception will be thrown).
what you should do is this
for text in file: # get one line of text
if createLogin == text.strip(): # compare the line with the user input string
print("Username already exists!")
break
.strip() removes any leading or trailing spaces in the database stored name (in this case the line break character \n used to denote the end of a line in the file. break ends the loop prematurely cos your lookup is complete since you found what you were looking for, and it would be an unnecessary to continue comparing the user input with other strings, imagine the txt had 1000 names and the 1st name was a match, the user would see the error printed but the program would continue running for the rest of the 999 tries, making it seem sluggish and waste unnecessary CPU cycles.
The database is still case sensitive however which may or may not be desired depending on your requirements. For case insensitivity you could do the following:
for text in file: # get one line of text
if createLogin.lower() == text.strip().lower(): # compare the line with the user input string
print("Username already exists!")
break
.lower() makes both strings into lower case strings and then checks if they are the same, eliminating the case sensitivity.
Instead of writing to the text file, try pickling the database.
This will save a representation of the object that you can easily load back into your program.
import pickle
users = {}
users["Ash"] = "password"
pickle.dump(users, open("users.p", "wb"))
loaded_users = pickle.load(open("users.p", "rb"))
print(loaded_users)
A more advanced solution may also be to check out a relational database, such as [sqlite3][1]
Before I state my question I would like to start by saying that I am a beginner at Python programming. I am about half way through my first ever programming class. With that being said I have also researched and used the search engines to look for information on the topic I am working on but I have not found anything that has been either helpful or specific enough to my problem. I have looked through Stack Overflow including browsing the similar questions dialogue. My hope is that this will not be down voted or marked as a duplicate before I get any helpful information.
I am creating a contacts manager program that uses a list of contact names, email addresses, and phone numbers stored in a CSV file. My program should allow the user to display a list of all the contact names, add/delete contacts, and view specific contact information. I am having trouble with the final requirement. Everything else in the program is working and displaying in the console like it should. The code for the entire program is found below;
#!/user/bin/env python3
# Contacts Manager Program
#Shows title of program at start.
print("The Contact Manager Program")
print()
#Imports CSV Module
import csv
#Defines global constant for the file.
FILENAME = "contacts.csv"
#Displays menu options for user, called from main function.
def display_menu():
print("COMMAND MENU")
print("list - Display all contacts")
print("view - View a contact")
print("add - Add a contact")
print("del - Delete a contact")
print("exit - Exit program")
print()
#Defines write funtion for CSV file.
def write_contacts(contacts):
with open(FILENAME, "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(contacts)
#Defines read function for CSV file.
def read_contacts():
contacts = []
with open(FILENAME, newline="") as file:
reader = csv.reader(file)
for row in reader:
contacts.append(row)
return contacts
#Lists the contacts in the list with the user inputs the "list" command.
def list_contacts(contacts):
for i in range(len(contacts)):
contact = contacts[i]
print(str(i+1) + ". " + contact[0])
print()
#List a specific contacts information when the user inputs the "view" command.
def view_contact(number):
#Adds contact to the end of the list when user inputs the "add" command.
def add_contact(contacts):
name = input("Name: ")
email = input("Email: ")
phone = input("Phone: ")
contact = []
contact.append(name)
contact.append(email)
contact.append(phone)
contacts.append(contact)
write_contacts(contacts)
print(name + " was added.\n")
#Removes an item from the list.
def delete_contact(contacts):
number = int(input("Number: "))
if number < 1 or number > len(contacts): #Display an error message if the user enters an invalid number.
print("Invalid contact number.\n")
else:
contact = contacts.pop(number-1)
write_contacts(contacts)
print(contact[0] + " was deleted.\n")
#Main function - list, view, add, and delete funtions run from here.
def main():
display_menu()
contacts = read_contacts()
while True:
command = input("Command: ")
if command.lower() == "list":
list_contacts(contacts)
elif command.lower() == "view": #Store the rest of the code that gets input and displays output in the main function.
view_contact(contacts)
elif command.lower() =="add":
add_contact(contacts)
elif command.lower() == "del":
delete_contact(contacts)
elif command.lower() == "exit":
break
else:
print("Not a valid command. Please try again.\n")
print("Bye!")
if __name__ == "__main__":
main()
I need the view_contact function to get a number as input from the user and then print the corresponding contact information that is related the the line number in the CSV file.
It looks like you storing contacts in form of lists in your .csv file. Use read_contacts to read all the contacts from that csv file, then get contact specified by number parameter. That's it.
def view_contact(number):
contacts = read_contacts()
specified_contact = contacts[number]
print("Name: ", specified_contact[0])
print("Email: ", specified_contact[1])
print("Phone: ", specified_contact[2])
I am trying to create a python program to save my friends' birthdays and access them easily and check for birthdays each day(I am not great at remembering dates and I never use facebook), but when I add a new birthday it is only accessible until I end the program - it then disappears again. I have been struggling with this for a while now and would really appreciate help fixing the error. Thanks!
import time
import pickle
def main():
birthday_file = open('birthdays_dict.dat','ab')
birthday_doc = open('birthdays_dict.dat','rb')
birthdays = pickle.load(birthday_doc)
date = time.strftime("%m/%d")
again = 'y'
while again.lower() == 'y' or again.lower() == 'yes':
choice = menu_choice()
if choice == 1:
name = add_name()
birthday = add_birthday()
birthdays[name] = birthday
print(name)
print(birthday)
pickle.dump(birthdays,birthday_file)
elif choice == 2:
print('Birthdays today(' + date + '):')
birth_today = {}
for key, value in birthdays.items():
if value == date:
print(key)
elif choice == 3:
search_name = input('Enter name to search: ')
print()
if search_name in birthdays:
print(birthdays[search_name])
if birthdays[search_name] == date:
print('Their birthday is today!')
else:
print('Not found')
else:
print('Not a valid selection!')
print()
again = go_again()
birthday_file.close()
birthday_doc.close()
Your problem is that you keep appending new dicts onto the file instead of replacing the old one, but then at startup you only load the very first one instead of all of them.
To fix this, you need to change this:
birthday_file = open('birthdays_dict.dat','ab')
… to this:
birthday_file = open('birthdays_dict.dat','wb')
But don't do that change on its own, because that will erase the file before you've read the old version!
You probably want to do something like this at the top of the function:
with open('birthdays_dict.dat', 'rb') as birthday_doc:
birthdays = pickle.load(birthday_doc)
I used a with statement so the file will automatically get closed right after the load, so it's definitely safe for us to overwrite it later.
Then later, when you want to write to the file, that's when you open it in w mode to erase the file and overwrite it with the new version—at which point you might as well close it immediately, because if you ever do write to it again, you're going to want to erase it again first, so let's use with again:
with open('birthdays_dict.dat', 'wb') as birthday_doc:
pickle.dump(birthdays, birthday_doc)
I am trying to create a registrar system through Python with pickles. I have gotten the system to record user input, but it does not save it for future implementations of the program.
Here is the code that will start the program:
import datetime
import pandas as pd
import pickle as pck
import pathlib
from pathlib import *
from registrar import *
prompt = "Please select an option: \n 1 Create a new course \n 2 Schedule a new course offering \n 3 List this school's course catalogue \n 4 List this school's course schedule \n 5 Hire an instructor \n 6 Assign an instructor to a course \n 7 Enroll a student \n 8 Register a student for a course \n 9 List this school's enrolled students \n 10 List the students that are registered for a course \n 11 Submit a student's grade \n 12 Get student records \n 13 Exit"
farewell = "Thank you for using the Universal University Registrar System. Goodbye!"
print ("Welcome to the Universal University Registration System.")
print ("\n")
try: #As long as CTRL-C has not been pressed, or 13 not been input by user.
input_invalid = True
while input_invalid:
inst = input("Please enter the name of your institution. ").strip()
domain = input("Please enter the domain. ").strip().lower()
if inst == "" or domain == "":
print("Your entry is invalid. Try again.")
else:
input_invalid = False
schoolie = Institution(inst, domain)
if Path(inst + '.pkl').exists() == False:
with open(inst + '.pkl', 'r+b') as iptschool:
schoolie = pck.load(iptschool)
while True:
print (prompt)
user_input = input("Please enter your choice: ")
try:
user_input = int(user_input)
if user_input < 1 or user_input > 14: #UserInput 14: on prompt.
raise ValueError("Please enter a number between 1 and 13, as indicated in the menu.")
except ValueError:
print("Not a valid number. Please try again.")
if user_input == 1: #Create a new course
input_invalid2 = True #Ensure that the user actually provides the input.
while input_invalid2:
input_name = input("Please enter a course name: ").strip()
input_department = input("Please enter the course's department: ").strip()
input_number = input("Please enter the course's number (just the number, not the departmental prefix): ").strip()
try:
input_number = int(input_number)
except ValueError:
print ("Please print an integer. Try again.")
input_credits = input("Please enter the number of credits awarded for passing this course. Please use an integer: ").strip()
try:
input_credits = int(input_credits)
except ValueError:
print ("Please print an integer. Try again.")
if input_name != "" and input_department != "" and input_number and input_credits:
input_invalid2 = False #Valid input
else:
print("One or more of your entries is invalid. Try again.")
added_course = Course(input_name, input_department, input_number, input_credits)
for course in schoolie.course_catalog:
if course.department == input_department and course.number == input_number and course.name == input_name:
print("That course is already in the system. Try again.")
input_invalid2 == True
if input_invalid2 == False:
schoolie.add_course(added_course)
print ("You have added course %s %s: %s, worth %d credits."%(input_department,input_number,input_name, input_credits))
And here is the second option, which SHOULD reveal that it is stored, but it does not.
elif user_input == 2: #Schedule a course offering
input_invalid2 = True #Ensure that the user actually provides the input.
while input_invalid2:
input_department = input("Please input the course's department: ").strip()
input_number = input("Please input the course's number: ").strip()
course = None
courseFound = False
for c in schoolie.course_catalog:
if c.department == input_department and c.number == input_number: #Course found in records
courseFound = True
course = c
input_section_number = input("Please enter a section number for this course offering: ").strip()
input_instructor = input("If you would like, please enter an instructor for this course offering: ").strip()
input_year = input("Please enter a year for this course offering: ").strip()
input_quarter = input("Please enter the quarter in which this course offering will be held - either SPRING, SUMMER, FALL, or WINTER: ").strip().upper()
if input_course != "" and input_course in schoolie.course_catalog and input_section_number.isdigit() and input_year.isdigit() and input_quarter in ['SPRING', 'SUMMER', 'FALL', 'WINTER'] and input_credits.isdigit():
if input_instructor != "": #Instructor to be added later, if user chooses option 6.
added_course_offering = CourseOffering(c, input_section_number, None, input_year, input_quarter)
else:
added_course_offering = CourseOffering(c, input_section_number, input_instructor, input_year, input_quarter)
schoolie.add_course_offering(added_course_offering)
input_invalid2 = False #Valid input
print ("You have added course %s, Section %d: %s, worth %d credits."%(input_course,input_section_number,input_name, input_credits))
else:
print("One or more of your entries is invalid. Try again.")
if courseFound == False: #If course has not been found at the end of the loop:
print("The course is not in our system. Please create it before you add an offering.")
break
By the way, I think I have the system closing properly. Correct me if I'm wrong:
elif user_input == 13: #Exit
with open(inst + '.pkl', 'wb') as output:
pck.dump(schoolie, output, pck.HIGHEST_PROTOCOL)
del schoolie
print (farewell)
sys.exit()
except KeyboardInterrupt: #user pushes Ctrl-C to end the program
print(farewell)
I believe that there is something wrong with the way that I am setting up the pickles files. I'm creating them, but I seem not to be putting data into them.
I apologize for the long-winded nature of this question, but I hope that the details will help you understand the problems that I've been having. Thanks in advance for the help!
it seems you may have dump and load reversed: (from the docs)
Signature: pck.load(file, *, fix_imports=True, encoding='ASCII', errors='strict')
Docstring:
Read and return an object from the pickle data stored in a file.
Signature: pck.dump(obj, file, protocol=None, *, fix_imports=True)
Docstring:
Write a pickled representation of obj to the open file object file.
With all those lines of code, it does get a little confusing, but I don't see any code that is pickling and writing the objects to a file.
Before anything else, you should assign the file to a variable so you can reference it. To do this, you'll have code similar to this:MyFile = open("FileName.extension","wb"). MyFile can be any name you want, it will be what you use later to reference the file. FileName is the name of the file itself. This is the name it will have in File Explorer. .extension is the file's extension, specifying the type of file. You should use .dat for this. wb is the file access mode. "w" means write, and "b" means binary. (Pickled objects can only be stored in a binary file.)
To write the pickled objects, you'll need this code:pck.dump(object,MyFile). (Usually, you would use pickle.dump(object,MyFile), but you imported pickle as pck.)
After writing the data to the file, you'll want to retrieve it. To do this, the "wb" instance of MyFile needs to be closed like this:MyFile.close(). Then you'll need to re-open the file in read mode using the following code:MyFile = open("FileName.extension","rb") Then you would use this:object = pickle.load(MyFile) to read the data. In the preceding example, (the load function), your object must have the same name as when you pickled it using the dump function. (pck.dump(object,MyFile))
In the end, you'll end up with something similar to this:
if writing conditions are true:
MyFile = open("FileName.dat","wb")
pickle.dump(object,MyFile) # This will be repeated for each object.
MyFile.close()
if reading conditions are true:
MyFile = open("FileName.dat","rb")
object = pickle.load(MyFile) # This will be repeated for each object.
MyFile.close()
I'm sorry if this wasn't the answer you wanted. Because of all those lines of code, it is somewhat hard to understand. I need clarification to give a better answer.