Writing dictionary output to file - Python - python

I have a small program to track monthly balances. This worked fine as is, and then I added in the section to write to a .txt file at the bottom. I did some searching but can't figure out a way to make it work. Basically I want to keep appending to this test.txt file. Every time I enter a new month/account/balance I want that appended to the file.
The alternative is to append to the test.txt file after 'exit', so it doesn't do it every loop. Not sure which way is more efficient
***EDIT****
This updated code now creates test.txt file but the file is blank after each loop
Secondary question - I have heard this would be better off using a Class for this, but I haven't any idea how that would look. If someone wants to demonstrate that would be awesome. This isn't homework, this is strictly learning on my own time.
Any ideas? Thanks
# create program to track monthly account balances
savings = []
def add_accounts(date, account, balance):
savings.append({'date': date, 'account': account, 'balance':
balance})
def print_accounts():
print(savings)
while True:
date = input('Enter the date, type exit to exit program: ')
if date == 'exit':
break
account = input('Enter the account: ')
balance = int(input('Enter the balance: '))
add_accounts(date, account, balance)
print_accounts()
with open('test.txt', 'a') as f:
for row in savings():
print (row)
f.write(str(savings[-1]))
file.close()

The problem with your original code is that print_accounts() doesn't return anything, yet you attempt to perform operations on its (nonexistent) return value.
Here is a version of your program made using classes, and with a few corrections:
class Account:
def __init__(self, id, date, balance):
self.id = id
self.date = date
self.balance = balance
def getString(self):
return self.id + "," + self.date + "," + str(self.balance)
savings = []
def add_account(date, account, balance):
savings.append(Account(date, account, balance))
def print_accounts():
for account in savings:
print(account.getString())
while True:
date = input("Enter the date, type exit to exit program: ")
if date.lower() == "exit":
break
else:
account = input('Enter the account: ')
balance = int(input('Enter the balance: '))
add_account(date, account, balance)
print_accounts()
with open("test.txt", "w") as file:
for account in savings:
file.write(account.getString() + "\n")
Some explanation regarding the class: The Account class has 3 fields: id, date, and balance. These fields are defined in the constructor (__init__()). The class also has a method, getString(), which I use to get the string representation of each instance.
Over all, the following changes have been made:
Create an Account class, which serves as the template for the object which holds the data of each account.
Use a loop to print accounts and write them to the file.
Turn date into lowercase before checking to see if it is equal to "exit". This is a minor change but a good habit to have.
Removed f.close(), as it is unnecessary when using a with open() statement.
Created a custom string representation of each instance of Account, consistent with what you would otherwise get.
That last one is achieved via defining the getString method in the account class. There is nothing special about it, it is merely what we use to get the string representation.
A better but quite more advanced way to achieve that is by overriding the __str__ and __repr__ methods of the base object. These are essentially hidden functions that every class has, but which python defines for us. The purpose of these two specific ones is to give string representations of objects. The default code for them doesn't produce anything meaningful:
<__main__.Account object at 0x0000000003D79A58>
However, by overriding them, we can use str() on instances of Account, and we will get a string representation in the exact format we want. The modified class will look like so:
class Account:
def __init__(self, id, date, balance):
self.id = id
self.date = date
self.balance = balance
def __repr__(self):
return self.id + "," + self.date + "," + str(self.balance)
def __str__(self):
return self.__repr__()
This also eliminates the need to loop through savings when writing to the file:
with open("test.txt", "w") as file:
for account in savings:
file.write(account.getString() + "\n")
Turns into:
with open("test.txt", "w") as file:
file.write(str(savings))
This wouldn't have worked before, as str() would have given us the gibberish data you saw earlier. However, now that we have overridden the methods, it works just fine.

Try this code (use -1 to exit):
savings = []
def add_accounts(date, account, balance):
savings.append({'date': date, 'account': account, 'balance':
balance})
def print_accounts():
print(savings)
while True:
date = input('Enter the date, type exit to exit program: ')
if date == -1:
break
account = input('Enter the account: ')
balance = int(input('Enter the balance: '))
add_accounts(date, account, balance)
print_accounts()
with open('test.txt', 'a') as f:
for row in savings:
print (row)
f.write(str(savings[-1]))
f.close()

Related

Input from user to print out a certain instance variable in python

I have created a class with programs:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
Channel 1, start:16.00 end:17.45 viewers: 100 name: Matinee:The kiss on the cross
Channel 1, start:17.45 end:17.50 viewers: 45 name: The stock market today
Channel 2, start:16.45 end:17.50 viewers: 30 name: News
Channel 4, start:17.25 end:17.50 viewers: 10 name: Home building
Channel 5, start:15.45 end:16.50 viewers: 28 name: Reality
I also have created a nested list with the programs:
[[1,16:00, 17,45, 100, 'Matinee: The kiss on the cross'],[1,17:45, 17,50, 45,'The stock market today'],[2,16:45, 17,50, 30,'News'], [4,17:25, 17,50, 10,'Home building'],[5,15:45, 16,50, 28,'Reality']
Now we want the user to be able to write the name of a program:
News
The result should be:
News 19.45-17.50 has 30 viewers
I thought about how you could incorporate a method to avoid the program from crashing if the input is invalid/ not an instance variable
I have tried this:
Check_input():
print('Enter the name of the desired program:')
while True: #Continue asking for valid input.
try:
name = input('>')
if name == #is an instance?
return name
else:
print('Enter a program that is included in the schedule:') #input out of range
except ValueError:
print('Write a word!') #Word or letter as input
print('Try again')
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory"
Do you have any suggestions how to combat the problem?
All help is much appreciated!
I wonder if I should separate all the program-names from the nested list and check if the user enters a name in the list as input? (Maybe by creating a for-loop to iterate over?)
Well if all your programs have a unique name then the easiest approach would probably be to store them in a dictionary instead of a nested list like:
programs = {
"News": Program("2", "16:45", "17:50", "News", "30", "60"),
"Reality": <Initialize Program class object for this program>,
...
}
Then you could just use the get dictionary method (it allows you to return a specific value if the key does not exist) to see if the asked program exists:
name = input('>')
program = programs.get(name, None)
if program:
print(program)
else:
# raise an exception or handle however you prefer
And if your programs don't have a unique name then you will have to iterate over the list. In which case I would probably return a list of all existing objects that have that name. A for loop would work just fine, but I would switch the nested list with a list of Program objects since you already have the class.
I also have a question regarding how to print out the selected program when the user enters the correct name? I understand how to rearrange them into the correct order to create the sentence. However, I don't know how to access the correct program in the "memory" Do you have any suggestions how to combat the problem.
I would say that the most elegant solution is to override the __str__ method of your Program class so that you can just call print(program) and write out the right output. For example:
class Program:
def __init__(self,channel,start, end, name, viewers, percentage):
self.channel = channel
self.start = start
self.end = end
self.name = name
self.viewers = viewers
def __str__(self):
return self.name + " " + self.start + "-" + self.end + " has " + self.viewers + " viewers"
should print out
News 19.45-17.50 has 30 viewers
when you call it like:
program = programs.get(name, None)
if program:
print(program)

How to create and access dynamic variable names a template function?

I wound up having three extremely similar functions in my code, which were to take separate user inputs for their birth year, month, and day. I want to use the best practices I can even though the code is extremely basic, which is why it's a bit overkill. So right now I have a function that acts as a template and takes three args dateType, typeStr, and typeFormat. I'm trying to use these args to name variables in the three functions that I'll create using the template so that I can later print out the birth date of the person. I'm aware of scope, but I've tried making things global etc etc and it hasn't worked. I don't know if I'm even creating variables that are persistent or if it all gets unassigned once the function is done, and if I am creating variables I can't figure out what they're called as I've tried every possibility.
def makeTemplateInput(dateType, typeStr, typeFormat):
def templateInput(dateType, typeStr, typeFormat):
print('You\'re using the template function. Please input your birth {} in the format {}.\n$ '.format(dateType, typeFormat), end='')
while True:
try:
dateType = input()
typeStr = dateType
dateType = int(dateType)
if dateType > 0:
if len(typeStr) != len(typeFormat) and isinstance(dateType, int):
print('Your input doesn\'t have {} digits, please use the format {}.\n$ '.format(str(len(typeFormat)), typeFormat), end='')
print('strlen: ' + str(len(typeStr)))
continue
break
else:
print('Your input is not a positive integer!\n$ ', end='')
continue
except ValueError:
print('Your input is not a valid number, please use the format {} where {} is an integer.\n$ '.format(typeFormat, str(typeFormat[:1])), end='')
print(dateType)
def yearInput1():
makeTemplateInput('year', 'yearStr', 'YYYY')
yearInput1()
print('Your birthdate is: {}/{}/{}'.format(yearInput1.year, monthInput.monthStr, dayInput.dayStr))
I'm sure it's a mess that misunderstands fundamental things about Python, but I really don't understand what's gone wrong.
A few online classes or some good books can help with some of this confusion. I've created some sample code to hopefully answer your question. Thank you.
class Calendar:
def __init__(self, day, month, year): #This can be initialised with the day/month/year
self.day = day
self.month = month
self.year = year
def displayDate(self): #This will display the dates from the object created/set
print('day:{} month:{} year:{}'.format(self.day, self.month, self.year))
def setNewDate(self, otherDay, otherMonth, otherYear): #this sets the class attributes to something else
print('This was the old values day:{} month:{} year:{}'.format(self.day, self.month, self.year))
self.day = otherDay
self.month = otherMonth
self.year = otherYear
print('The new values are day:{} month:{} year:{}'.format(self.day, self.month, self.year))
cal = Calendar(6,11,2020)
cal.displayDate()
cal.setNewDate(3,4,2099)

Python creating an Object while reading file

I wrote a simple Python script to determine if all students grades are reported. The script first loops through and adds students to arrays regarding grade status. Then I loop through the file again, to determine if each students grades are in. I end up with three arrays that include students with "all grades reported", "some grades reported", "no grades reported". However, I want tackle this problem with more of a object oriented approach. I have attempted to create a class that works. I am stuck at how to loop through and create one Object for each student, then use addcourse to push each course into the Object. Any help I can get to become a better programmer would be great!
Data:
**id,fname,lname,course,grade,mode**
10001,Freddy,Freshman,Art-101,A,online
10001,Freddy,Freshman,Art-101,A,online
10002,Suize,Sophmore,Mat-102,C,inperson
10002,Suize,Sophmore,Bio-101, ,inperson
10002,Suize,Sophmore,Soc-201,D,online
10003,Jilly,Junior,mth-102, ,inperson
10003,Jilly,Junior,Bus-101, ,inperson
10003,Jilly,Junior,Che-204, ,inperson
Working Code:
fh = open('students.txt').readlines()
header = fh.pop(0)
gradereported = []
nogradereported = []
for line in fh:
students = line.split(',')
ids = students[0]
grade = students[4]
if grade != "":
gradereported.append(ids)
else:
nogradereported.append(ids)
allgradesin =[]
nogradesin = []
somegradesin = []
for i in fh:
students = line.split(',')
ids = students[0]
if ids in gradereported and ids not in nogradereported:
if ids not in allgradesin:
allgradesin.append(ids)
elif ids not in gradereported and ids in nogradereported:
if ids not in nogradesin:
nogradesin.append(ids)
elif ids in gradereportedand and ids in nogradereported:
if ids not in somegradesin:
somegradesin.append(ids)
Attempt at class:
class Student(object):
def __init__(self, lname, fname, term, courses = []):
self.studid = studid
self.lname = lname
self.fname = fname
self.term = term
self.courses = []
def addcourse(self, course, grade, mode):
self.course = course
self.grade = grade
self.mode = mode
self.courses.append((self.course, self.grade, self.mode))
You could do this, as #blade suggests, by creating a dictionary indexed by student id and then for each row of your input file either get the existing student from the dictionary if it exists or create a new one. In code, this would look like:
class Student(object):
def __init__(self, student_id, lname, fname):
self.studid = student_id
self.lname = lname
self.fname = fname
self.courses = []
def addcourse(self, course, grade, mode):
self.courses.append((course, grade, mode))
students = {}
fh = open('students.txt').readlines()
header = fh.pop(0)
for line in fh:
row = line.split(',')
if len(row) < 6:
continue
student_id, fname, lname, course, grade, mode = [i.strip() for i in row]
student = students.get(student_id, Student(student_id, lname, fname))
student.addcourse(course, grade, mode)
students[student_id] = student
A couple of things to note. First, I modified the constructor of your Student class, dropping the term argument since it wasn't clear where the term was specified in your input file. Furthermore, since you don't use the courses argument I dropped that as well. (Note that you probably don't want to use [] as a default argument. Read about mutable default arguments here.) You also don't need to create instance variables for the course, grade, and mode in your addcourse function, you can just append them directly to the array.
I also added a call to strip for each of the items pulled from the input file to clean up the newlines at the end of each row.
How about this:
Add a dict that id is the key, and the Student object is the value
Loop the file and if the key is in the dict, get the Student object from the dict. Otherwise create a new Student object. Then add the course to the Student object.
In addition to the answer of #JCVanHanne you could define another function in your class to collect the info, whether a student has none, some or all of his/her grades.
One possible way (assuming a missing grade is represented by an empty string while also grades like A+ or other none-empty values are possible) could be:
def gradeStatus(self):
miss = [course[1] for course in self.courses].count("") # count empty grades
if len(self.courses) == miss:
print('No grades at all')
elif miss in range(1, len(self.courses)):
print('Some, but not all grades')
elif miss == 0:
print('All grades provided')
else:
print('Invalid Data')
You probably would use status codes or other ways (like a return value to further process) to work with the information than just printing them. As an example with the print commands:
students['10003'].gradeStatus() # leads to: No grades at all

Can't get python to read/display my variable

I have been working on this one program for hours now and I am still having no luck. I am trying to create a "search engine" where you can look products with a SKU number.
class SKU:
def __init__(self, name, product):
self.name = name
self.product = product
def displaySKU(self):
print "Sku Number : ", self.name, ", Product: ", self.product
sku90100 = SKU("90100", "10310, 00310")
sku90101 = SKU("90101", "10024, 00024")
sku90102 = SKU("90102", "10023")
sku90103 = SKU("90103", "10025")
sku90104 = SKU("90104", "10410")
search = input("Please type SKU Number")
if search in range(90100, 90106):
"sku",search.displaySKU
My problem is that I can't seem to get display the SKU information; I have tried removing, changing, and adding characters to the variables without success. I may have missed something thou, but all I now is that nothing that I try works. Please help me figure this out, and thank you for taking the time to read my question.
Instead of storing each product as its own variable, use a dict:
skus = {}
skus[90100] = SKU("90100", "10310, 00310")
skus[90101] = SKU("90101", "10024, 00024")
skus[90102] = SKU("90102", "10023")
skus[90103] = SKU("90103", "10025")
skus[90104] = SKU("90104", "10410")
Then you can check membership using in, and call the .displaySKU() method to print:
if search in skus:
skus[search].displaySKU()
Lastly, for Python 2, it's preferred to use raw_input instead of input. raw_input gives you a string though, so you want to convert that to an int to match your skus keys:
search = int(raw_input("Please type SKU Number"))

How do I access a class instance in a list when there is multiple classes?

I'm a beginning programmer who is building a program that simulates a bank with multiple bank accounts that a user can withdraw/deposit cash, create accounts, get exchange rates, etc. Currently, I'm trying to access a group of instances in my class that are all objects of my account class. The Account Manager class is responsible for managing these account objects and helping to organize them when user input is required. Right now, I'm trying to simulate my 3rd option on my menu which gets info on the account of a user's choice(they must manually put the ID of their account in in order to retrieve information on it, withdraw/deposit cash, etc.). Although I've managed to store all of these class instances in a list, I can't seem to use my get_account method to retrieve these for use. I'll post all of my code below. If you see anything else that is out of place, feel free to let me know.
Code:
# Virtual Bank
# 3/21/13
# Account Manager Class
class AccountManager(object):
"""Manages and handles accounts for user access"""
# Initial
def __init__(self):
self.accounts = []
# create account
def create_account(self, ID, bal = 0):
# Check for uniqueness? Possible method/exception??? <- Fix this
account = Account(ID, bal)
self.accounts.append(account)
def get_account(self, ID):
for account in self.accounts:
if account.ID == ID:
return account
else:
return "That is not a valid account. Sending you back to Menu()"
Menu()
class Account(object):
"""An interactive bank account."""
wallet = 0
# Initial
def __init__(self, ID, bal):
print("A new account has been created!")
self.id = ID
self.bal = bal
def __str__(self):
return "|Account Info| \nAccount ID: " + self.id + "\nAccount balance: $" + self.bal
# Main
AccManager = AccountManager()
def Menu():
print(
"""
0 - Leave the Virtual Bank
1 - Open a new account
2 - Get info on an account
3 - Withdraw money
4 - Deposit money
5 - Transfer money from one account to another
6 - Get exchange rates(Euro, Franc, Pounds, Yuan, Yen)
"""
) # Add more if necessary
choice = input("What would you like to do?: ")
while choice != "0":
if choice == "1":
id_choice = input("What would you like your account to be named?: ")
bal_choice = float(input("How much money would you like to deposit?(USD): "))
AccManager.create_account(ID = id_choice,bal = bal_choice)
Menu()
elif choice == "2":
acc_choice = input("What account would you like to access?(ID only, please): ")
AccManager.get_account(acc_choice)
print(acc_choice)
Menu()
Your Account objects don't actually seem to have ID attributes; instead, they have id attributes. Python is case-sensitive; try changing if account.ID == ID to if account.id == ID.
EDIT:
You are also returning after the very first mismatch. You need to remove one level of indentation from your else block so that you get through the entire loop first, and in fact, your else block shouldn't even be an else block, since you're not actually matching an if; the method should only fail if none of the accounts match the given ID.
EDIT 2:
Also, you're not actually assigning the return value from get_account() to anything, so it's lost. I'm not exactly sure what you expect to happen there.
The error lies in lines 31 and 35. You have written "id" instead of "ID". Fully capitalize those two things such that:
class Account(object):
"""An interactive bank account."""
wallet = 0
# Initial
def __init__(self, ID, bal):
print("A new account has been created!")
self.ID = ID
self.bal = bal
def __str__(self):
return "|Account Info| \nAccount ID: " + self.ID + "\nAccount balance: $" + self.bal
Please let us know if the code works after that.

Categories