Loop in a class and writing to a txt file - python

I am trying to figure out a way to store songdata as a list in a .txt. The method I am using seems to be storing the values somewhere, but its not writing them to the file. I also am trying to insert a loop into it so I can keep entering "songs" instead of only one. I haven't used classes before and I cant quite grasp how it would be done. I maybe am going about it wrong and need to reformat parts? Any advice would be awesome.
class Song:
def __init__(self,song,chart,member):
self.song = song
self.chart = chart
self.member = member
def __str__(self):
return self.song + " topped the charts at " + str(self.chart)+ " band memebers include " + str(self.member)
songdata = Song(input("song"),input("chart spot"), input("bandemember"))
def readstring(f, line):
string = line.strip('\r\n')
return string
def writestring(f, string):
f.write(string)
with open("string.txt", "a+", encoding="utf-8") as f:
cont = "Y"
while cont.upper() == "Y":
d = input(songdata)
if d != "q":
string = " "+d
writestring(f, string)
else:
print("saving.....")
break
f.seek(0)
for line in f:
print(readstring(f,line))
f.close()

Couple of notes:
Because you only initialised the class once when you request the information from you user in the code d = input(songdata), the prompt from input will always display the same thing after the first time.
The reason why nothing is being written to file is probably because the response from d=... is always blank from the user. You requested the song information when you initialised the class (which you only did once), but never wrote that to file (instead you wrote f.write(string), where string=" "+d)
As mentioned in the replies, you don't really need a specific function to write to file when you can just call the file descriptors write() method.
I've re-written some of your code (the writing to file parts) below. I assumed you wanted the user to be able to exit the program at any time by entering in the key sequence q, and have done so accordingly. You can make something more nifty with generators I believe, but this isn't related to the problem:
class Song:
"""
song class
"""
def __init__(self, song, chart, member):
self.song = song
self.chart = chart
self.member = member
def __str__(self):
return (self.song
+ " topped the charts at "
+ str(self.chart)
+ " band memebers include "
+ str(self.member)
+ '\n'
)
def main():
with open("string.txt", "a+", encoding="utf-8") as fd:
#Loop until user requests to stop
#Key sequence to stop = 'q'
while(1):
#Get user input
prompt = ">>\t"
in_song = input("song" + prompt)
if (in_song == 'q'):
break
in_chart_spot = input("chart spot" + prompt)
if (in_chart_spot == 'q'):
break
in_band_mem = input("band members" + prompt)
if (in_band_mem == 'q'):
break
#Create the class
song_data = Song(in_song, in_chart_spot, in_band_mem)
#Write out the data
fd.write(str(song_data))
if __name__ == '__main__':
main()
Hope this helps :)

Related

Saving to CSV file when using Class attribute

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()

How can I prevent my JSON file from getting overwritten in Python?

I am currently building a school homework project - a contact manager, using classes in Python.
I was able to assemble all the needed parts to make my code work, yet upon exiting the program with Terminal, the data inside of my JSON file keep being overwritten.
I've tried changing the with open attribute to "w" and "a", sadly nothing works.
Main Code:
from colorama import Fore, Style
from LoadAndSave import load_file, save_file
from ContactBook import ContactBook
contacts = []
DATA_FILE = "contactbook.json"
def menu():
print(Fore.RED + "Welcome to Contacts Manager v2.0.0!" + Style.RESET_ALL)
print(Fore.LIGHTCYAN_EX + "Please enter your selection according to the menu." + Style.RESET_ALL)
print("a - Add a contact")
print("r - Remove a contact")
print("s - Search for a contact")
print("p - Print a list of all contacts")
print("x - Exit")
user_selection = input(Fore.GREEN + "Your selection: " + Style.RESET_ALL)
return user_selection
def main():
load_file(DATA_FILE)
contactbook = ContactBook()
user_selection = ""
while user_selection != "x":
user_selection = menu() # As long as user did not select "x", program will always run.
if user_selection == "a":
contactbook.add_contact(input("Please enter contact's name: "), int(input("Please enter contact's number: ")))
if user_selection == "r":
contactbook.remove_contact(contactbook.search_contact(input("Contact's Name? ")))
if user_selection == "s":
contactbook.search_contact(input("Contact's name?"))
print(Fore.GREEN + "Success!" + Style.RESET_ALL)
if user_selection == "p":
print(contactbook)
print(Fore.GREEN + "Success!" + Style.RESET_ALL)
print(Fore.MAGENTA + "Thank you for using my software. Bye!")
save_file(contactbook.make_contact_json(), DATA_FILE)
if __name__ == "__main__":
main()
Load and save:
import json
def load_file(DATA_FILE): # Loading JSON file with all information
with open (DATA_FILE) as file:
return json.load(file)
def save_file(json_list, DATA_FILE):
with open (DATA_FILE, "w") as file:
json.dump(json_list, file, indent = 4)
Contact & ContactBook classes:
import json
class Contact:
name = ""
tel = 0
def __init__(self, name = "", tel = 0):
self.name = name
self.tel = tel
def __str__(self):
return json.dumps({"contact_info":[{"name": self.name, "tel": self.tel}]})
from colorama import Fore, Style, Back
from Contact import Contact
import json
class ContactBook:
contacts = []
def __init__(self):
pass
def add_contact(self, name = "", tel = 0):
self.contacts.append(Contact(name, tel))
print(Fore.GREEN + "Success!" + Style.RESET_ALL)
def remove_contact(self, contact_name):
self.contacts.remove(contact_name)
print(Fore.RED + "Removed.\n" + Style.RESET_ALL)
def search_contact(self, contact_name):
for contact in self.contacts:
if type(contact) is Contact:
if contact.name == contact_name:
return contact
return (Back.RED + "\nThere is no contact with that name." + Style.RESET_ALL + "\n")
def make_contact_json(self):
result = []
for contact in self.contacts:
result.append(json.loads(contact.__str__()))
return result
def __str__(self) -> str:
result = ""
for contact in self.contacts:
result += contact.__str__()
return result
JSON File:
[
[
{
"name": "sdfgh",
"tel": 654321
}
]
]
Thanks in advance to all helpers!
Your contacts are getting overwritten because every time you run your program, you are creating a fresh ContactBook
contactbook = ContactBook() # In your Main Code
This in turn initializes an empty contacts list
contacts = [] # Inside Class ContactBook
I suggest that you add an __init__ logic to you ContactBook Class that initialises your contacts list with the existing ones
Something Like
class ContactBook:
def __init__(self, existing_contacts=None):
self.contacts = [] if existing_contacts is None else existing_contacts
Also while creating the ContactBook object in you main code please pass the existing contacts.
try:
existing_contacts = load_file(DATA_FILE)
except FileNotFoundError:
existing_contacts = None
contactbook = ContactBook(existing_contacts)
Also please make sure that you are saving the contacts correctly. It seems to currently be a list of list of objects where as it should ideally be a list of objects
Hope you get good grades. Peace out.

Im having trouble editing an object in OOP in my project

Basically im doing a project in python as part of my full stack course, and i have ran into wall.
My project is a parking lot system, which gets you a ticket with your cars number, unique code, time entered. At the exit you will have to write the unique code and it will calculate the cost for the parked time. I created a class named Key which creates the object it self with the exit time as None, but my trouble begins by trying to update the self.exit which doesn't work out for me using the the function exit_time. Every time a car enters the data is written to a file using pickle, i tried using a list to be able to edit the object but something isn't working out for me.
Also I tried many varieties by calling the function or what happens in the function it self.
THIS IS MY MAIN
list_of_cars = []
while True:
startmessage() # prints message
choice() # prints message
action = input("\nYour choice: ")
if action == "1":
choice_one() # prints message
car_number = input(" here: ")
new_client = Key(car_number)
list_of_cars.append(new_client)
writing_file(list_of_cars)
reading_file()
if action == "2":
choice_two() # prints message
exit_key = input(" here: ")
Key(exit_key).exit_time(exit_key)
READ AND WRITE
def reading_file():
with open("parking.data", "rb") as readfile:
list_of_cars = pickle.load(readfile)
print("testing", [str(x) for x in list_of_cars])
readfile.close()
return list_of_cars
def writing_file(list_of_cars):
with open("parking.data", "wb") as myfile:
pickle.dump(list_of_cars, myfile)
myfile.close()
return list_of_cars
THE CLASS
import random
import pickle
import datetime as dt
class Key:
def __init__(self, car_number):
self.car_number = car_number
self.key = self.generate()
self.enter = self.enter_time()
self.exit = None
"""
creates the key it self and while creating it checks if it already exists so that there will be no duplicates
"""
def generate(self):
key = ""
chunk = ""
alphabet = "ABCDEFGHIJKLMNOPQRZTUVWXYZ1234567890"
while True:
while len(key) < 8:
char = random.choice(alphabet)
key += char
chunk += char
if len(chunk) == 3:
key += "-"
chunk = ""
key = key[:-1]
with open("parking.data", "rb") as readfile:
new_list = pickle.load(readfile)
if key in new_list:
key = ""
else:
return key
def __str__(self):
return f"{self.car_number},{self.key}," \
f"{self.enter},{self.exit}"
def enter_time(self):
start = str(dt.datetime.now().strftime('%H:%M:%S'))
return start
def exit_time(self, exit_key):
from read_and_write import reading_file
list_of_cars = reading_file()
if exit_key in list_of_cars:
self.exit = str(dt.datetime.now().strftime('%H:%M:%S'))
print("IT WORKED!!!")
print("got to the function :/")
your conditional is:
if exit_key in list_of_cars:
exit_key is OM7-XVX
list_of_cars is ['5412,OM7-XVX,21:09:42,None1',...]
So...
'OM7-XVX' in ['5412,OM7-XVX,21:09:42,None1'] -> False
'OM7-XVX' in ['5412,OM7-XVX,21:09:42,None1'][0] -> True
Therefore replace the conditional with
if any(exit_key in v for v in list_of_cars):

Running a dictionary with a while loop

I am trying to insert a while loop into this program so when it asks for member it starts a dictionary (assuming I would use a dictionary) that lets me input n number of band members and the instrument they use in some form like (name,instrument),(name2,instrument2)..and so on. I know it will be run as a while loop, but I'm not not sure how to enter it in this instance. Would using a dictionary be the best action and if so how would I add it in a case like this?
class Song:
def __init__(self, song, chart, member):
self.song = song
self.chart = chart
self.member = member
def __str__(self):
return (self.song
+ " Top Chart:"
+ str(self.chart)
+ " Band Members: "
+ str(self.member)
+ '\n')
def write():
with open("string.txt", "a+", encoding="utf-8") as f:
while(1):
prompt = ":\t"
in_song = input("Input song or type q " + prompt)
if (in_song == 'q'):
break
in_chart_spot = input("Input chart spot" + prompt)
in_band_mem = input("Input band members" + prompt)
song_data = Song(in_song, in_chart_spot, in_band_mem)
#albumdata = Album()
f.write(str(song_data))
if __name__ == '__main__':
write()

Saving of Information in Python Along with Retrieving It

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.

Categories

Resources