Whenever my methods are supposed to be advancing to the next line in a txt file that I am importing, they instead decide to continuously use the same line instead of advancing to the next line in the document.
DUMMY = 9999
def readMaster():
#opens the customers file, sets a variable to whatever line we are on
infile=open("customers.txt", 'r')
line=infile.readline()[:-1]
#checks if entered ID is valid. If it is, return their name and balance. if not, return garbage.
if line!=(""):
masterID,masterName,balance=line.split(",")
return int(masterID),masterName,int(balance)
else:
masterID=DUMMY
return masterID,"",0
infile.close()
def readTransaction():
#opens the transactions files
infile=open("transactions.txt","r")
#scans through the transactions file. If Item ID is found, return that line
#if it isn't, return garbage variables.
line=infile.readline()[:-1]
if line!=(""):
itemID,itemName,cost=line.split(",")
return int(itemID),itemName,int(cost)
else:
itemID=DUMMY
return itemID,"",0
infile.close()
def updateRecords():
#creates a new file for us to write to.
outfile = open("new_master.txt", 'w')
#pulls in any values we need for calculation
masterID,masterName,balance = readMaster()
itemID,itemName,cost=readTransaction()
#checks to see if the customer's ID matches the ID of the service purchased. To avoid printing multiple lines
#per person, we use a while loop to continue adding to the balance until the customer didn't buy the next item.
#Then, asks for the next line in the transaction text.
if int(itemID)==int(masterID):
while int(itemID)==int(masterID):
balance = balance+cost
return int(itemID),itemName,int(cost)
# Since the customers.txt and transactions.txt files are both sorted numerically, we check to see
# if one is greater than the other. If it is, that means a customer didn't make any purchases, so we
# print that person's line from customers.txt without updating it
elif itemID>masterID:
print(masterID+","+masterName+","+balance,file =outfile)
# If we don't find any transactions for something, an error is printed.
else:
print("No record for item",itemID)
print(masterID + "," + masterName + "," + balance, file=outfile)
itemID,itemName,cost=readTransaction()
#Then, we print the customer's ID, name, and new balance to the new text file
print (masterID+","+masterName+","+balance,file = outfile)
Customers.txt
207,Ann Wyeth,120
215,David Fisher,89
412,Deb Washington,75
609,Lily Ahn,110
610,Dottie Sturgis, 39
1984,Leslie Jackson,109
1989,Taylor Grandview,55
1999,Roger Nelson,65
2112,Lee Geddy,99
5150,Valerie Edwards,45
7800,John Bongiovi,160
transactions.txt
207,Formal Styling,55
207,Partial Highlights,65
215,Haircut,29
610,Formal Styling,55
610,Accent Highlights,50
1999,Clipper Cut,19
2112,Haircut with Shampoo,39
5150,Haircut with Styling,45
5150,Partial Highlights,65
5150,Treatments,29
6792,Coloring,150
7800,Haircut,29
You're not looping over the file's contents. In each of your methods your opening the file and then doing a readline, so it seems you're asking it to repeatedly open the file and read only the first line. For example, in readMaster you think it's doing:
opens the customers file, sets a variable to whatever line we are on
But that's not the case. You're opening the file, reading one line of it, checking for a null string, and then returning some tuple before closing the file. No matter how many times you call this method, it will only ever read the first line.
Since you're basically doing the same sort of read operation on both files (returning the int(line[0]),line[1],int(line[2]) for each line, you can use a single method (if you needed to process differently, you could use boolean switch based on the filename, etc.):
def readFile(filename):
# returns data from specified file
with open(filename, 'r') as infile:
lines = [line.trim() for line in infile.readlines()]
lines = [(int(ln[0]),ln[1],int(ln[2])) for ln.split(',') in lines if ln else (masterID,'',0)]
return lines
I'm not sure what sort of output you expect, but I have some idea this might be what you're after:
customers = r'c:\debug\customers.txt'
transactions = r'c:\debug\transactions.txt'
outputFile = r'c:\debug\new_master.txt'
def readFile(filename):
DUMMY = 9999
default = [DUMMY,'',0]
# opens the customers file, and returns a list of tuple OR
# opens the transactions file and returns a list of tuple
with open(filename, 'r') as infile:
lines = [line.strip().split(',') for line in infile.readlines()]
lines = [ln[:3] if ln else default for ln in lines]
return lines
def updateRecords():
"""
checks to see if the customer's ID matches the ID of the service purchased.
To avoid printing multiple lines per person, add to the balance for each matching id.
"""
#pulls in any values we need for calculation
master = readFile(customers)
trans = readFile(transactions)
#creates a new file for us to write to.
outfile = open(outputFile, 'w')
for (id,name,bal) in master:
balance = int(bal)
balance += sum(int(itmCost) for (itmID,itmName,itmCost) in trans if itmID == id)
# now we have the balance for THIS id from customer file
if balance == int(bal):
# If we don't find any transactions for something, an error is printed.
# balance hasn't changed, no transaction for this customer, log to console
print("No record for item {}".format(id))
# update the new master file:
outfile.write('{},{},{}\n'.format(id,name,balance))
outfile.close()
And produces the following output file:
207,Ann Wyeth,240
215,David Fisher,118
412,Deb Washington,75
609,Lily Ahn,110
610,Dottie Sturgis,144
1984,Leslie Jackson,109
1989,Taylor Grandview,55
1999,Roger Nelson,84
2112,Lee Geddy,138
5150,Valerie Edwards,184
7800,John Bongiovi,189
Related
everyone. I have a Python assignment that requires me to do the following:
Download this CSV fileLinks to an external site of female Oscar winners (https://docs.google.com/document/d/1Bq2T4m7FhWVXEJlD_UGti0zrIaoRCxDfRBVPOZq89bI/edit?usp=sharing) and open it into a text editor on your computer
Add a text file to your sandbox project named OscarWinnersFemales.txt
Copy and paste several lines from the original file into your sandbox file. Make sure that you include the header.
Write a Python program that does the following:
Open the file and store the file object in a variable
Read the entire contents line by line into a list and strip away the newline character at the end of each line
Using list slicing, print lines 4 through 7 of your file
Write code that will ask the user for an actress name and then search the list to see if it is in there. If it is it will display the record and if it is not it will display Sorry not found.
Close the file
Below is the code I currently have. I've already completed the first three bullet points but I can't figure out how to implement a search function into the list. Could anyone help clarify it for me? Thanks.
f = open('OscarsWinnersFemales.txt')
f = ([x.strip("\n") for x in f.readlines()])
print(f[3:7])
Here's what I tried already but it just keeps returning failure:
def search_func():
actress = input("Enter an actress name: ")
for x in f:
if actress in f:
print("success")
else:
print("failure")
search_func()
I hate it when people use complicated commands like ([x.strip("\n") for x in f.readlines()]) so ill just use multiple lines but you can do what you like.
f = open("OscarWinnersFemales.txt")
f = f.readlines()
f.close()
data = {} # will list the actors and the data as their values
for i, d in enumerate(data):
f[i] = d.strip("\n")
try:
index, year, age, name, movie = d.split(",")
except ValueError:
index, year, age, name, movie, movie2 = d.split(",")
movie += " and " + movie2
data[name] = f"{index}-> {year}-{age} | {movie}"
print(f[3:7])
def search_actr(name):
if name in data: print(data[name])
else: print("Actress does not exist in database. Remember to use captols and their full name")
I apologize if there are any errors, I decided not to download the file but everything I wrote is based off my knowledge and testing.
I have figured it out
file = open("OscarWinnersFemales.txt","r")
OscarWinnersFemales_List = []
for line in file:
stripped_line = line.strip()
OscarWinnersFemales_List.append(stripped_line)
file.close()
print(OscarWinnersFemales_List[3:7])
print()
actress_line = 0
name = input("Enter An Actress's Name: ")
for line in OscarWinnersFemales_List:
if name in line:
actress_line = line
break
if actress_line == 0:
print("Sorry, not found.")
else:
print()
print(actress_line)
This is currently my code for reading through a CSV file, Creating a person object, and adding each person to a list. One line Example input: John,Langley,1,2,2,3,5
When i print(per) each time after creating a person object. My output is correct, but as soon as i add that person to the list i made, the numeric values AKA 'traits' for that person are all the same as the last persons traits in the CSV file.
For Example:
John,Langley,1,2,2,3,5 --(add to list)-->John,Langley,1,1,1,1,1
Isabel,Smith,3,2,4,4,0 --(add to list)-->Isabel,Smith,1,1,1,1,1
John,Doe,1,1,1,1,1 --(add to list)-->John,Doe,1,1,1,1,1
This is impacting me with continuing because i need the person objects' traits to be valid in order to perform analysis on them in the next couple methods. PLEASE IGNORE MY PRINT STATEMENTS. THEY WERE FOR MY DEBUGGING PURPOSES
def read_file(filename):
file = open(filename, "r", encoding='utf-8-sig')
Traits_dict = {}
pl = []
next(file)
for line in file:
line = line.rstrip('\n')
line = line.split(',')
first = str(line[0].strip())
last = str(line[1].strip())
w = line[2].strip()
hobby = line[3].strip()
social = line[4].strip()
eat = line[5].strip()
sleep = line[6].strip()
Traits_dict["Work"] = w
Traits_dict["Hobbies"] = hobby
Traits_dict["Socialize"] = social
Traits_dict["Eat"] = eat
Traits_dict["Sleep"] = sleep
per = Person(first, last, Traits_dict)
print(per)
pl.append(per)
print(pl[0])
print(pl[1])
print(pl[2])
print(pl[3])
print(pl[4])
return pl
All the Traits_dict = {} are the same to all object since you initiating the dict before the loop so it's giving each Person object the same dict reference in it.
You can put the Traits_dict = {} inside the loop that it will create each Person a new dict
for line in file:
Traits_dict = {}
I'm making a program that stores data in a text file, I can search for data line by line, and I made a (delete function) that is quoted below, making a variable 'a' adding to it the (non deleted lines), and ask before deletion for results and if not confirmed it would be added also to 'a', then rewrite the (file) with'a' omitting the deleted lines.
THE PROBLEM IS:
all results are deleted not only the confirmed one desbite that:
#deleting line
confirm = input('confirm to delete [y]/[n]>>')
if confirm != 'y':
a += line
so, why did this problem happen and how to fix it?
Next is the whole code of delete function:
searching = input('enter any information about query: ')
searching = searching.lower() # converting words in lower case
f = open(file, 'r')
lines = f.readlines()
f.close()
print('Word | Definition | Remarks')
a = '' # we will store our new edited text here
for line in lines:
line_lower_case = line.lower() # changing line in lower case temporary
# because contact != COntact and will not appear in searcch
if searching in line_lower_case:
print('Query found')
print()
print('>>',line, end = '') # printing words in the same case as been added
# end = '', to prevent printing new line avoiding extra empty line
#deleting line
confirm = input('confirm to delete [y]/[n]>>')
if confirm != 'y':
a += line
#elif confirm =='y':
# pass # it will just do nothing, and will not add line to 'a'
continue # to search for more queries with the same searching entry
print()
a += line #we add each line to the 'a' variable
f = open(file,'w')
f.write(a) #we save our new edited text to the file
f.close()
I changed the indentations of the program and that was the issue as I agreed with #TheLazyScripter and that should work now if I understood your problem correctly, I did a bunch of tests and they did work. I noticed that you didn't define what input file will be and I add that line of code at line 3 which will through an error if the file not defined.
searching = input('enter any information about query: ')
searching = searching.lower() # converting words in lower case
file = "test.txt" #your file
f = open(file, 'r')
lines = f.readlines()
f.close()
print('Word | Definition | Remarks')
a = '' # we will store our new edited text here
for line in lines:
line_lower_case = line.lower() # changing line in lower case temporary
# because contact != COntact and will not appear in searcch
if searching in line_lower_case:
print('Query found')
print()
print('>>',line, end = '') # printing words in the same case as been added
# end = '', to prevent printing new line avoiding extra empty line
#deleting line
confirm = input('confirm to delete [y]/[n]>>')
if confirm != 'y':
a += line
#elif confirm =='y':
# pass # it will just do nothing, and will not add line to 'a'
continue # to search for more queries with the same searching entry
print()
a += line #we add each line to the 'a' variable
f = open(file,'w')
f.write(a) #we save our new edited text to the file
f.close()
I am making a program for my computer science assignment. I need to make a quiz for 3 classes in a primary school. Then the results have to be saved in a file. I've done the program till here but the next task asks me to let each student have 3 turns and give an average for each one.
here is the code I used to save the results into a text file:
def savetofile():
result = result ="\n "+ namestudent.get() + " "fscore.get()+"/4"
messagebox.showinfo("results", "your results been saved successfuly")
if int(year.get())==1:
f = open('results C1.txt', 'a')
f.write(result)
f.close()
if int(year.get())==2:
f = open('results C2.txt', 'a')
f.write(result)
f.close()
if int(year.get())==3:
f = open('results C3.txt', 'a')
f.write(result)
f.close()
how can I check if the new user taking the quiz has already done the quiz or not and how can I add the new results of that person in front of their name also how can I take the average of their 3 sets of score.
first of all, you output your results been saved successfully before writing to a file, which is not true, because the file writing can fail and thus not end up done successfully.
Then you do open and close your file in the following way:
f = open('results C1.txt', 'a')
f.write(result)
f.close()
which is wrong as well because if the write fails for any reason (like an exception reading the result variable), the file won't be closed properly, and the output may not get flushed to it.
You should instead do:
with open('results C1.txt', 'a') as f:
f.write(result)
which will take care of opening, flushing and closing the file correctly.
Then the following line is wrong:
result = result ="\n "+ namestudent.get() + " "fscore.get()+"/4"
as it misses a + between the spaces and the score result. You'd better write something like (with the \n at the end to avoid having an empty first line):
result = "{} {}/4\n".format(namestudent.get(), fscore.get())
how can I check if the new user taking the quiz has already done the quiz or not?
To do it you need to do the following algorithm:
# to open the file:
with open('results C1.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
if name == namestudent.get():
# do something when the student exists
how can I add the new results of that person in front of their name also how can I take the average of their 3 sets of score?
Then my suggestion for this is to not work directly with the files, but instead open up a "cache" dictionary of all the scores:
def load_scores():
years_tuple_default = (None, None, None) # create a tuple with as many entries as there can be years
student_scores = dict()
with open('results C1.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[0] = score
with open('results C2.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[1] = score
with open('results C3.txt', 'r') as results:
# read the file
for result in results:
# split the line
name, score = result.split(" ")
student_scores.setdefault(name, years_tuple_default)[2] = score
return student_scores
Then, create a function save the cache into the files:
def save_scores(student_scores):
with open('results C1.txt', 'w') as results_y1:
with open('results C2.txt', 'w') as results_y2:
with open('results C3.txt', 'w') as results_y3:
for student, scores in student_scores:
results_y1.write("{} {}/4\n".format(student, scores[0]))
results_y2.write("{} {}/4\n".format(student, scores[1]))
results_y3.write("{} {}/4\n".format(student, scores[2]))
print("Results saved!")
And finally, work against that cache:
def update_scores(student_scores, namestudent, fscore, year):
if namestudent.get() not in student_scores.keys():
# add the student entry
student_scores.setdefault(namestudent.get(), (None, None, None))[int(year.get())-1] = fscore.get()
else:
# update the student year entry
student_scores[int(year.get())-1] = fscore.get()
which would end up with a code looking like that to put it all together:
student_scores = load_scores()
# do your stuff to get the namestudent/fscore/year data
update_scores(student_scores, namestudent, fscore, year)
# when all updates are done, you can alter the files
save_scores(student_scores)
To sum up:
split your algorithm into functions,
protect your file handling using the with statement
read the files once to create a "cache" to work against, and save the result at once when you're done
Bonus ideas
use a class
From there, to get further, you could create a class, and have all that as methods:
class StudentScores:
def __init__(self):
self._student_scores = dict()
def load_scores(self):
# TODO
def save_scores(self):
# TODO
def update_score(self):
# TODO
And then calculating the mean of the scores is simple stupid, it's just adding a method to the class which prototype would look like:
class StudentScores:
…
def get_mean_scores(self, student):
score_y1, score_y2, score_y3 = self._student_scores[student]
score = # calculate the average of the three score
return score
use a with statement
And if you want to shine, you could implement it as working with the with statement:
class StudentScores:
def __init__(self):
self._student_scores = dict()
def load_scores(self):
# TODO
def save_scores(self):
# TODO
def update_score(self):
# TODO
def __enter__(self):
self.load_scores()
return self
def __exit__(self, type, value, traceback):
self.save_scores()
And then your code would like that:
with StudentScores() as student_scores:
# do your stuff to get the namestudent/fscore/year data
update_scores(student_scores, namestudent, fscore, year)
To conclude, I'm showing you how I'd design something to do your assignment, whereas I'm not trying to do your assignment on your behalf. My goal here is to help you get ideas and learn something about software design and python. Some things may be above your current level (like how to create a with statement), but as you're learning, you'll be able to fully understand and apply everything I'm telling you here.
HTH
I have a problem where the function just overwrites the line thats already there in a .txt file. The function is supposed to write a highscore to a file when the game quits (I have made a snake game by following a youtube tutorial). I can't quite figure out why it won't start on a new line, can anyone please explain the logic behind it, and how I fix it? I read somewhere that instead of "w" in f.open(), I should type "rb" or something. Since I'm kinda new to this "writing-to-file" thingy, I find it difficult.
Also, I want to sort the highscores from highest to lowest in the file (in other words, sort finalScore from highest to lowest). I have no idea how I should go on and code that, so I'd appreicate some help. You see, I want to print out the current highscores to the console (in order to make a scoreboad)
Heres the code:
import random
import time
name = "Andreas"
finalScore = random.randint(1,10)
def scoreToFile(finalScore):
#Has to be generated here, since we need the exact current time
currentTime = time.strftime("%c")
print("Sucsessfully logged score (finalScore) to highscores.txt")
f = open("highscores.txt", "w")
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
f.write(line + "\n")
f.close()
scoreToFile(finalScore)
Anyways, merry christmas my fellow python geeks! :D
1) one option is to open the file in append mode.
replace:
f = open("highscores.txt", "w")
with:
f = open("highscores.txt", "a")
2) another option is to replace this block,
f = open("highscores.txt", "w")
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
myfile.write(line + "\n")
f.close()
and use a with style
with open("highscores.txt", "a") as myfile:
#fileOutput = [(currentTime, ":", name, "-", finalScore)]
fileOutput = [(finalScore, "-", name, currentTime)]
for t in fileOutput:
line = ' '.join(str(x) for x in t)
myfile.write(line + "\n")
I prefer the second style as it is more safe and clean.
Mode w overwrites an existing file; mode 'a' appends to it. Also, the best way to handle a file is usually with the with statement, which ensures the closing on your behalf; so:
fileOutput = [(finalScore, "-", name, currentTime)]
with open("highscores.txt", "a") as f:
for t in fileOutput:
line = ' '.join(str(x) for x in t)
f.write(line + "\n")
For sorting, you need be able to extract the final score as a number from a line:
def minus_score(line):
return -int(line.split()[0])
then the total work will be done as:
def sorted_by_score():
with open("highscores.txt", "r") as f:
result = list(f)
return sorted(result, key=minus_score)
This will give you a list lines sorted in ascending order of score (the latter's the reason score is negating the number, though one might also choose to have it just return the number and reverse the sorting), for you to loop on and further process.
Added: so on the OP's request here's how the whole program might be (assuming the existence of a function that either plays a game and returns player name and final score, or else returns None when no more games are to be played and the program must exit).
import time
def play_game():
""" play a game and return name, finalscore;
return None to mean no more games, program finished.
THIS function you'd better code yourself!-)
"""
def scoreToFile(name, finalScore):
""" Add a name and score to the high-scores file. """
currentTime = time.strftime("%c")
fileOutput = finalScore, "-", name, currentTime
line = ' '.join(str(x) for x in fileOutput)
with open("highscores.txt", "a") as f:
f.write(line + "\n")
def minus_score(line):
""" just for sorting purposes, not called directly. """
return -int(line.split()[0])
def sorted_by_score():
""" return list of score lines sorted in descending order of score. """
with open("highscores.txt", "r") as f:
return sorted(f, key=minus_score)
def main():
while True:
game_result = play_game()
if game_result is None: break
scoreToFile(*game_result)
for line in sorted_by_score:
print(line.strip())
As others have mentioned, the problem is you're not opening the file in append mode, so it overwrites it every time rather than adding to it.
However, if you also want to keep the data in the file sorted, you do want to overwrite it each time, since the order of its contents will likely have been changed with the addition. To do that requires first reading it contents in, updating the data, and then writing it back out.
Here's a modified version of your function that does that. I also changed how the data in file is stored to what is known as Comma (or Character) Separated Values (CSV) format, because Python includes acsvmodule which makes it very easy to read, write, and do other things with such files.
import csv
import random
import time
highscores_filename = "highscores.txt"
HighScoresFirst = True # Determines sort order of data in file
def scoreToFile(name, finalScore):
currentTime = time.strftime("%c")
# Try reading scores from existing file.
try:
with open(highscores_filename, "r", newline='') as csvfile:
highscores = [row for row in csv.reader(csvfile, delimiter='-')]
except FileNotFoundError:
highscores = []
# Add this score to the end of the list.
highscores.append([str(finalScore), name, currentTime])
# Sort updated list by numeric score.
highscores.sort(key=lambda item: int(item[0]), reverse=HighScoresFirst)
# Create/rewrite highscores file from highscores list.
with open(highscores_filename, "w", newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='-')
writer.writerows(highscores)
print("successfully logged score (finalScore) to highscores.txt")
# Simulate using the function several times.
name = "Name"
for i in range(1, 4):
finalScore = random.randint(1,10)
scoreToFile(name + str(i), finalScore)
time.sleep(random.randint(1,3)) # Pause so time values will vary.