Ok so I am trying really hard to get this working. I think I am still not so familiar with the self argument yet, not sure if that matters in this case but I want to append user input once I choose number 1 in the menu and input data that appends to user_list and eventually saves in csv file. But I only get the code <main.User object at 0x7f36d7ccdfa0> in the csv file once I put in the data throught the program
import csv
user_list = []
class User:
def __init__(self, first, last):
self.first = first
self.last = last
self.email = first + '.' + last + '#expressdelivery.com'
def menu():
while True:
print("[1]. Add/remove/update: user to the system.")
try:
option = int(input("Choose from the menu: "))
if option == 1:
user_list.append(User(first = input("Name: "), last = input("Last: ")))
with open('User.csv', 'w') as file:
writer = csv.writer(file)
writer.writerow(user_list)
return(menu())
else:
print("Program quits")
break
except:
print("Error")
menu()
Related
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)
I have a text file set out in this layout:
Greg,Computer Science,Hard,5
Alex,Computer Science,Medium,2
Fiona,Maths,Easy,0
Cassie,Maths,Medium,5
Alex,Maths,Medium,1
In my program I want the user to be able to choose a certain name and see their results. My code for this looks like this:
name = input("Enter name: ")
for each in file:
each = each.split(",")
realName = each[0]
subject = each[1]
difficulty = each[2]
score = each[3]
if name == realName:
print(subject, difficulty, score)
break
else:
print()
print("Invalid name.")
name = input("Re-enter your name: ")
A few things are wrong with it though and I can't figure out what to do:
If the user entered "Alex", only one of his results will be displayed.
If a wrong name is inputted once, every other name inputted will return as "Invalid".
If the correct name is inputted and the results are displayed, the program will continue to ask for a name.
Does anybody have any solutions to these problems?
If you're going to query your file repeatedly, I'd recommend pre-loading your data once into a dictionary, and printing data as and when needed. Something like this:
data = {}
with open('file.txt', 'r') as file:
for line in file:
realName, subject, difficulty, score = each.split(',')
data.setdefault(realName, []).append((subject, difficulty, score))
while True:
name = input('>>> ')
data.get(name, 'Invalid Name')
This solves problems one and two. If you just want to break after the first valid name is input, you can query the return value of dict.get:
while True:
name = input('>>> ')
result = data.get(name)
if result:
print(result)
break
print('Invalid name')
This solves problem three.
You're better off using the csv module since your file syntax is simple CSV.
Then you can loop through the rows (each row will be an array of values).
import csv
def parse_csv_file(csv_file, operation, value, index):
with open(csv_file, newline='') as file:
reader = csv.reader(file, delimiter=',',
quotechar='|')
return operation(reader,
value, index)
def find_first_row(csv_reader, value, index):
for row in csv_reader:
if row[index] == value:
return row
return None
def main():
query = input('Enter a name: ')
result = parse_csv_file('file.csv',
find_first_row,
query, 0)
if result:
print(result)
else:
print('Nothing found!')
main()
#!/usr/bin/env python3
import csv
# a file in the current directory
FILENAME = "contacts.csv"
def write_contacts(contacts):
with open(FILENAME, "w", newline="") as file:
writer = csv.writer(file)
writer.writerows(contacts)
def read_contacts():
contacts = []
with open(FILENAME, newline="") as file:
reader = csv.reader(file)
for row in reader:
contacts.append(row)
return contacts
def list_contacts(contacts):
for i in range (len(contacts)):
contact= contacts[i]
print(str(i+1) +"."+ contact[0])
print()
def view_contact(contacts):
pos = int(input("Number: "))
if not (pos-1)in range(len(contacts)):
print(str(pos) + ' not in list, try again')
view(contacts)
return
contact = []
print(name + email + phone+".\n")
print()
def delete_contact(contacts):
index = int(input("Number: "))
contact = contacts.pop(index -1)
write_contacts(contacts)
print(contact[0]+" was deleted.\n")
def add_contact(contacts):
name=input("Name: ")
email=input("Email: ")
phone=input("Phone number: ")
contact= []
contact.append(name)
contact.append(email)
contacts.append(contact)
write_contacts(contacts)
print(name + " was added.\n")
def display_menu():
print("Contact Manager")
print()
print("COMMAND MENU")
print("list - List all contacts")
print("view - View a contact")
print("add - Add a contact")
print("delete- Delete a contact")
print()
print()
def main():
display_menu()
contacts = read_contacts()
while True:
command = input("Command: ")
if command.lower() == "list":
list_contacts(contacts)
elif command.lower()== "view":
view_contact(contacts)
elif command.lower()== "add":
add_contact(contacts)
elif command.lower()== "delete":
delete_contact(contacts)
break
else:
print("Not a valid command. Please try again.\n")
print("Bye!")
if __name__ == "__main__":
main()
This all my code. I'm trying to figure out how to make the delete and view commands display an error message when the user enters a number that is invalid but it's not working. I'm also trying to view a contact when the user selects a specific number form list which would then display the email name and phone number of that selected number. I'm currently stuck
The errors im getting are
raceback (most recent call last):
, line 93, in
main()
, line 81, in main
view_contact(contacts)
, line 32, in view_contact
view(contacts)
NameError: name 'view' is not defined
I don't think you has a good start with list into cvs using append, anyway is your example.
You can use remove to remove your contact from list, see examples with list: http://www.thegeekstuff.com/2013/06/python-list
when the user select a specific number from list , just read by stepping to the number phone because you add with: name + email + phone.
adding an error message , use: try except finally
I am new to python, and trying to create a program which opens a csv file. The user is supposed to enter a barcode , then the program finds that product and the cost of the product. However I got an error which is the title of my thread. Here is my code.
import csv # imports should go at the top of the file
def read_csv_file():
""" reads csv data and appends each row to list """
csv_data = []
with open("task2.csv") as csvfile:
spamreader = csv.reader(csvfile, delimiter=",", quotechar="|")
for row in spamreader:
csv_data.append(row)
return csv_data
def get_user_input():
""" get input from user """
while True:
try:
GTIN = int(input("input your gtin-8 number: "))
break
except:
print ("Oops! That was not a valid number. Try again")
def search_user_input():
""" search csv data for string """
search_user_input
gtin = get_user_input()
for row in PRODUCT_DATA:
#print(row) #debug print
if row[0] == str(gtin):
product = row[1]
price = round(float(row[2]),2)
print(product, price)
return(product, price)
repeat = input("not in there? search again? If so (y), else press enter to continue")
if repeat == 'y':
search_user_input() # calls function again in order to create a loop
def quantity():
gtin = 0
product = 0
price = 0.0
product_data = read_csv_file()
product,price = search_user_input()
product, price = search_user_input(str(gtin), product_price)
order = int(input("How much of " + product + " do you want?"))
price = round(price * order, 2)
print(quantity,price)
def order_making():
print("Apples")
PRODUCT_DATA = read_csv_file() # call function to read csv
quantity() # call the main function
I have cleaned the flow up a bit for search_user_input and quantity. In some cases you were calling search_user_input with multiple arguments (it doesn't accept them) and you made it recursive. I have added some comments in the code below. In fact, that function was returning None in your setup, which leads to the TypeError: 'NoneType' object is not iterable error.
The if __name__ == '__main__:' is not necessary in your code, I've included it more as a heads-up for later on when you'll want to start importing your own modules. See this for more info on this topic.
import csv
def read_csv_file():
""" reads csv data and appends each row to list """
csv_data = []
with open("task2.csv") as csvfile:
spamreader = csv.reader(csvfile, delimiter=",", quotechar="|")
for row in spamreader:
csv_data.append(row)
return csv_data
def get_user_input():
""" get input from user """
while True:
try:
GTIN = int(input("input your gtin-8 number: "))
return GTIN # Breaks the loop and returns the value
except:
print ("Oops! That was not a valid number. Try again")
def search_user_input(product_data): # Pass the csv data as an argument
""" search csv data for string """
keep_searching = True
while keep_searching:
gtin = get_user_input()
for row in product_data:
if row[0] == str(gtin):
product = row[1]
price = round(float(row[2]),2)
return(product, price)
repeat = input("not in there? search again? If so (y), else press enter to continue")
if repeat != 'y':
keep_searching = False
return None # This is done implicitly, I'm just making it obvious
def quantity():
product_data = read_csv_file()
matches = search_user_input(product_data)
if matches: # Will not be True if search_user_input returned None
product, price = matches[0], matches[1]
order = int(input("How much of {} do you want?".format(product)))
price = round(price * order, 2)
print("That costs {}".format(price))
if __name__ == '__main__': # You'll need this in future for importing modules
# There was no need to read the csv_data here and make it global
quantity() # call the main function
The purpose of the two programs is to have twitter.py manage tweet.py by having the 5 most recent tweets that are saved in the program twitter.py to show up once you search and find it. There are four options, make a tweet, view recents tweets, search a tweet and quit. I'm having trouble saving because it keeps saying no recent tweets are found. Also I'm having trouble with the fact that I can't search for my tweets but that is probably the same reason as my first problem because they aren't being saved correctly. Thank you please help!!
tweet.py
import time
class tweet:
def __init__(self, author, text):
self.__author = author
self.__text = text
self.__age = time.time()
def get_author(self):
return self.__author
def get_text(self):
return self.__text
def get_age(self):
now = time.time()
difference = now - self.__time
hours = difference // 3600
difference = difference % 3600
minutes = difference // 60
seconds = difference % 60
# Truncate units of time and convert them to strings for output
hours = str(int(hours))
minutes = str(int(minutes))
seconds = str(int(seconds))
# Return formatted units of time
return hours + ":" + minutes + ":" + seconds
twitter.py
import tweet
import pickle
MAKE=1
VIEW=2
SEARCH=3
QUIT=4
FILENAME = 'tweets.dat'
def main():
mytweets = load_tweets()
choice = 0
while choice != QUIT:
choice = get_menu_choice()
if choice == MAKE:
add(mytweets)
elif choice == VIEW:
recent(mytweets)
elif choice == SEARCH:
find(mytweets)
else:
print("\nThanks for using the Twitter manager!")
save_tweets(mytweets)
def load_tweets():
try:
input_file = open(FILENAME, 'rb')
tweet_dct = pickle.load(input_file)
input_file.close()
except IOError:
tweet_dct = {}
return tweet_dct
def get_menu_choice():
print()
print('Tweet Menu')
print("----------")
print("1. Make a Tweet")
print("2. View Recent Tweets")
print("3. Search Tweets")
print("4. Quit")
print()
try:
choice = int(input("What would you like to do? "))
if choice < MAKE or choice > QUIT:
print("\nPlease select a valid option.")
except ValueError:
print("\nPlease enter a numeric value.")
return choice
def add(mytweets):
author = input("\nWhat is your name? ")
while True:
text = input("what would you like to tweet? ")
if len(text) > 140:
print("\ntweets can only be 140 characters!")
continue
else:
break
entry = tweet.tweet(author, text)
print("\nYour tweet has been saved!")
def recent(mytweets):
print("\nRecent Tweets")
print("-------------")
if len(mytweets) == 0:
print("There are no recent tweets. \n")
else:
for tweets in mytweets[-5]:
print(tweets.get_author, "-", tweets.get_age)
print(tweets.get_text, "\n")
def find(mytweets):
author = input("What would you like to search for? ")
if author in mytweets:
print("\nSearch Results")
print("----------------")
print(tweet.tweet.get_author(), - tweet.tweet.get_age())
print(tweet.tweet.get_text())
else:
print("\nSearch Results")
print("--------------")
print("No tweets contained ", author)
def save_tweets(mytweets):
output_file = open(FILENAME, 'wb')
pickle.dump(mytweets, output_file)
output_file.close()
main()
In twitter.py:add_tweets, mytweets is passed into the function and entry is created, but it is never added to mytweets. The created entry is lost after the function returns.
Your question was:
I'm having trouble saving because it keeps saying no recent tweets are
found.
Function add does not seem to be adding tweets anywhere. It creates a tweet.tweet instance, but it does not do anything with it.
You probably want to add the tweet to mytweets?
Another problem:
You initialize mytweets as a dicionary (tweet_dct = {}), but later you use it as a list (mytweets[-5]). It should be a list from start. And you probably want last five tweets (mytweets[-5:]), not just the fifth from the end.
On the sidenotes:
What you have here is not "two programs" - it is one program in two python files, or "modules"
Although there is nothing wrong with having getters (functions like get_author), there is no need for them in Python (see How does the #property decorator work?). Do youself a favour and keep it simple, e.g.:
class Tweet:
def __init__(self, author, text):
self.author = author
self.text = text
self.creation_time = time.time()
def get_age_as_string(self):
# your code from get_age
There will be time when you need private variables. When that happens, use a single leading underscore (self._author) until you fully understand what double underscore does and why.
Pickle is probably not the best way to store information here, but it is a good start for learning.