My assignment was to write a program which extracts the first/last names, birth year, and ID from a file, manipulate that information to create a username and formatted ID, prompt the user for 3 test grades, calculate the average, and finally write all the information to a new file. This is the program I wrote, and the error I got is listed below the program.
Define main function
def main():
infile = open("studentinfo.txt", "r")
data = infile.read()
fName, lName, ID, year = data.split(",")
year = int(year)
Prompt the user for three test scores
grades = eval(input("Enter the three test scores separated by a comma: "))
Create a username
uName = (lName[:4] + fName[:2] + str(year)).lower()
converted_id = ID[:3] + "-" + ID[3:5] + "-" + ID[5:]
grade_1, grade_2, grade_3 = grades
Convert the grades to strings so they can be written to a new file
[grade_1, grade_2, grade_3] = [str(grade_1), str(grade_2), str(grade_3)]
Calculate the average
average =(grade_1 + grade_2+ grade_3)/3
Convert the average to a string
average = str(average)
Write the information the file
outfile = open("studentreport.txt", "w")
outfile.write("*******Student Report*******\nStudent Name:" + fName + " " + lName)
outfile.write("\nStudent ID: " + converted_id + "\n" + "Username: " + uName + "\n\n")
outfile.write("Grade 1: " + grade_1 + "\n" "Grade 2: " + grade_2 + "\n" + "Grade 3: " + grade_3 + "\n" + "Average: " + average)
infile.close()
outfile.close()
main()
Traceback (most recent call last):
File "C:/Users/ovi/Desktop/Python Project 1.py", line 34, in
main()
File "C:/Users/ovi/Desktop/Python Project 1.py", line 22, in main
average =(grade_1 + grade_2+ grade_3)/3
TypeError: unsupported operand type(s) for /: 'str' and 'int'
You need to convert your converted string grades to floats (or int)
average =(float(grade_1) + float(grade_2)+ float(grade_3))/3.0
average = str(average)
You need to convert the variables of type int to strings.
outfile.write("Grade 1: " + str(grade_1) + "\n" "Grade 2: " + str(grade_2) + "\n" + "Grade 3: " + str(grade_3) + "\n" + "Average: " + str(average))
OR
You could simply do like this..
>>> gr1 = 23
>>> gr2 = 45
>>> gr3 = 56
>>> total = gr1+gr2+gr3
>>> avg = total/3
>>> l = [gr1, gr2, gr3, total, avg]
>>> print("GRade 1: {} grade 2: {} grade 3: {} total: {} average : {}".format(*l))
GRade 1: 23 grade 2: 45 grade 3: 56
Related
This is my file text:
Covid-19 Data
Country / Number of infections / Number of Death
USA 124.356 2.236
Netherlands 10.866 771
Georgia 90 NA
Germany 58.247 455
I created a function to calculate the ratio of deaths compared to the infections, however it does not work, because some of the values aren't floats.
f=open("myfile.txt","w+")
x="USA" + " " + " " + "124.356" + " " + " " + "2.236"
y="Netherlands" + " " + " " + "10.866" + " " + " " + "771"
z="Georgia" + " " + " " + "90" + " " + " " + "NA"
w="Germany" + " " + " " + "58.247" + " " + " " + "455"
f.write("Covid-19 Data" + "\n" + "Country" + " " + "/" + " " + "Number of infections" + " " + "/" + " " + "Number of Death" + "\n")
f.write(x + "\n")
f.write(y + "\n")
f.write(z + "\n")
f.write(w)
f.close()
with open("myfile.txt", "r") as file:
try:
for i in file:
t = i.split()
result=float(t[-1])/float(t[-2])
print(results)
except:
print("fail")
file.close()
Does someone have an idea how to solve this problem ?
You can do the following:
with open("myfile.txt", "r") as file:
for i in file:
t = i.split()
try:
result = float(t[-1]) / float(t[-2])
print(result)
except ValueError:
pass
At the time you don't know if the values you are trying to divide are numeric values or not, therefore surrounding the operation with a try-catch should solve your problem.
If you want to become a bit more "clean" you can do the following:
def is_float(value):
try:
float(value)
except ValueError:
return False
return True
with open("myfile.txt", "r") as file:
for i in file:
t = i.split()
if is_float(t[-1]) and is_float(t[-2]):
result = float(t[-1]) / float(t[-2])
print(result)
The idea is the same, however.
I used the same file that you attached in your example. I created this function hopefully it helps:
with open("test.txt","r") as reader:
lines = reader.readlines()
for line in lines[2:]:
line = line.replace(".","") # Remove points to have the full value
country, number_infections, number_deaths = line.strip().split()
try:
number_infections = float(number_infections)
number_deaths = float(number_deaths)
except Exception as e:
print(f"[WARNING] Could not convert Number of Infections {number_infections} or Number of Deaths {number_deaths} to float for Country: {country}\n")
continue
ratio = number_deaths/number_infections
print(f"Country: {country} D/I ratio: {ratio}")
As you can see I avoided the headers of your file using lines[2:] that means that I will start from row 3 of your file. Also, added try/exception logic to avoid non-float converts. Hope this helps!
Edit
Just noticed that the format for thousands is used with "." instead "," in that case the period was removed in line 7.
The results for this execution is:
Country: USA D/I ratio: 0.017980636237897647
Country: Netherlands D/I ratio: 0.07095527332965212
[WARNING] Could not convert Number of Infections 90.0 or Number of Deaths NA to float for Country: Georgia
Country: Germany D/I ratio: 0.007811561110443456
Fixed the following:
The first two lines in your text-file are headers. These need to be skipped
'NA' Can't be converted to zero
If there is a 0 in your data, your program would crash. Now it wouldn't.
f=open("myfile.txt","w+")
x="USA" + " " + " " + "124.356" + " " + " " + "2.236"
y="Netherlands" + " " + " " + "10.866" + " " + " " + "771"
z="Georgia" + " " + " " + "90" + " " + " " + "NA"
w="Germany" + " " + " " + "58.247" + " " + " " + "455"
f.write("Covid-19 Data" + "\n" + "Country" + " " + "/" + " " + "Number of infections" + " " + "/" + " " + "Number of Death" + "\n")
f.write(x + "\n")
f.write(y + "\n")
f.write(z + "\n")
f.write(w)
f.close()
with open("myfile.txt", "r") as file:
#Skipping headers
next(file)
next(file)
try:
for i in file:
t = i.split()
#Make sure your code keeps working when one of the numbers is zero
x = 0
y = 0
#There are some NA's in your file. Strings not representing
#a number can't be converted to float
if t[1] != "NA":
x = t[1]
if t[2] != "NA":
y = t[2]
if x == 0 or y == 0:
result = 0
else:
result=float(x)/float(y)
print(t[0] + ": " + str(result))
except:
print("fail")
file.close()
Output:
USA: 55.615384615384606
Netherlands: 0.014093385214007782
Georgia: 0
Germany: 0.12801538461538461
Your header line in the file is Covid-19 Data. this is the first line and when you call t=i.split() you then have a list t which has data ['Covid-19', 'Data']
you cannot convert these to floats since they have letters in them. Instead you should read the first 2 header line before the loop and do nothing with them. However you are then going to have issues with Georgia as "NA" also cannot be converted to a float.
A few other points, its not good practice to have a catch all exception. Also you dont need to close the file explicitly if you open the file using a with statement.
I am new to Python. What my code is supposed to do is check the line against an existing list, if the line is not already in the location file it asks for the user to assign a value to it and updates the list it is validating against. I have verified that the lists are reading from the text files correctly (in the below format).
The result it is giving me is a never-ending loop because it is not finding the line in the list even after it has been added. I would expect it to break after the user enters 'n' and then some string value.
(Also there will be an additional line for if dummyvar in location:, but I haven't gotten to that yet.)
Variables
from_location = [ company, address, city, state ] #changes line by line
location = [[ 'company a', 'address a', 'city a', 'state a', 'classification a'],
[ 'company b', 'address b', 'city b', 'state b', 'classification b']]
loc_opt = ['classification a', 'classification b', 'classification c']
Code snippet:
while from_location not in location[:][0:-1]:
ftext=("This location has not been indexed. Please enter the " +
"location name or input one of these prompts \n" +
" 'l' to list all acceptable locations\n" +
" 'n' to add a new location\n" +
" 'p' to print the full line of information\n" +
"Company: " + str(from_location[0]) + " \n" +
"Address: " + str(from_location[1]) + "\n" +
"City: " + str(from_location[2]) + "\n" +
"State: " + str(from_location[3]) + "\n")
dummyvar = input(ftext)
if dummyvar == "l":
print("Current Location Options are: \n ")
for item in loc_opt:
print(" ", item ," ")
if dummyvar == "p":
print("Entire Line : ", spline,"\n")
if dummyvar == "n":
new_location=input("Please input new location:\n")
new_location.upper()
new_location = [new_location]
loc_opt = loc_opt + new_location
location = location + [from_location + new_location]
print(location)
Full Code
print("Press Ctrl C with the Python window selected \n"
"at any time to stop the program. A loud beep "
"will sound \n when the program is finished.\n\n")
date = 00000000
counter = 1
dummyvar="q"
ref_fp =(r"filepath")
loc_opt_fn = open(ref_fp + "LOCATION OPTIONS.txt")
loc_ref_fn = open(ref_fp + "LOCATION REFERENCE.txt")
loc_opt = loc_opt_fn.read().split("\n")
location = loc_ref_fn.read().split("\n")
for index in range(len(location)):
location[index]=location[index].split("\t")
while len(str(date))!= 8 or (date < 20180101 or date > 20301231):
date = input("What date is the file would you like to clean"
"( yyyymmdd year like: 20190227). \n\n")
date = str(date).strip()
try:
date = int(date)
except:
print("\nNo letters please!\n")
date = 000
fp1 = (r"anotherfilepath")
fp2 = ( r" filename.txt")
fpr= (r"yetanotherfilepath")
filepath = fp1 + str(date) + fp2
with open(filepath) as source:
for line in source:
line.strip("\n")
spline = line.split("\t")
if counter == 1:
spline.append("FROM")
spline.append("TO")
else:
spline.append("")
spline.append("")
if spline[0] == "NC":
#So we've added two columns, FROM and To
#And we are only operating on the lines that are NC
#Because that excludes the exceptions.
#Now we want to check and see if the From and
#To information is in the reference lists.
from_location=[spline[5],spline[7],spline[9],spline[10]]
to_location=[spline[13],spline[15],spline[17],spline[18]]
while from_location not in location[:][0:-1]:
ftext=("This location has not been indexed. Please enter the " +
"location name or input one of these prompts \n" +
" 'l' to list all acceptable locations\n" +
" 'n' to add a new location\n" +
" 'p' to print the full line of information\n" +
"Company: " + str(from_location[0]) + " \n" +
"Address: " + str(from_location[1]) + "\n" +
"City: " + str(from_location[2]) + "\n" +
"State: " + str(from_location[3]) + "\n")
dummyvar = input(ftext)
if dummyvar == "l":
print("Current Location Options are: \n ")
for item in loc_opt:
print(" ", item ," ")
if dummyvar == "p":
print("Entire Line : ", spline,"\n")
if dummyvar == "n":
new_location=input("Please input new location:\n")
new_location.upper()
new_location = [new_location]
loc_opt = loc_opt + new_location
location = location + [from_location + new_location]
print(location)
counter += 1
import winsound
winsound.Beep(600,500)
print("\n\n\n----------------------------Processing is finished.----------------------------\n\n\n")
location[:][0:-1]doesn't remove the last element from each element of location. It's equivalent to temp = location[:] followed by temp[0:-1]. temp is just a copy of location, and then it returns a list with all but the last element of that.
You can do what you want with a list comprehension:
while from_location not in [l[0:-1] for l in location]:
def main():
infile = open("studentinfo.txt", "rt")
data = infile.read()
fName, lName, ID, year = data.split(",")
year = int(year)
# Prompt the user for three test scores
grades = eval(input("Enter the three test scores separated by a coma: "))
# Prompt create a username
uName = (lName[:4] + fName[:2] + str(year)).lower()
converted_id = ID[:3] + "-" + ID[3:5] + "-" + ID[5:]
grade_1, grade_2, grade_3 = grades
# Convert the grades to strings so they can be written to a new file
[grade_1, grade_2, grade_3] = [str(grade_1), str(grade_2), str(grade_3)]
# Calculate the average
average =(float(grade_1) + float(grade_2)+ float(grade_3))/3.0
# Convert the average to a string
average = str(average)
# Write the information to the file
outfile = open("studentreport.txt", "w")
outfile.write("*******Student Report*******\nStudent Name:" + fName + " " + lName)
outfile.write("\nStudent ID: " + converted_id + "\n" + "Username: " + uName + "\n\n")
outfile.write("Grade 1: " + str(grade_1) + "\n" "Grade 2: " + str(grade_2) + "\n" + "Grade 3: " + str(grade_3) + "\n" + "Average: " + str(average))
infile.close()
outfile.close()
main()
How to make it run properly using a readable text file
this is all I get when I run the program help?
Enter the three test scores separated by a coma: 80,78,90,
>>> 80,78,90,
(80, 78, 90)
>>> main()
Enter the three test scores separated by a coma: 87,86,90
>>>
There may be some syntax issues, but I cannot test it since I do not have your files, but this may be inline with what you are thinking:
def get_grades(student_name):
grades = raw_input("Enter the three test scores for {0} separated by a coma: ".format(student_name)).split(',')
if len(grades) != 3:
print "must enter three grades"
return get_grades(student_name)
return float(grades[0]), float(grades[1]), float(grades[2])
with open("studentreport.txt", "w") as outfile:
outfile.write("*******Student Report*******\n")
with open("studentinfo.txt", "r") as infile:
for student in infile:
fName, lName, ID, year = student.split(",")
year = int(year)
uName = "{0}{1}{2}".format(lName[:4], fName[:2], str(year)).lower()
converted_id = "{0}-{1}-{2}".format(ID[:3], ID[3:5], ID[5:])
# Prompt the user for three test scores
grade_1, grade_2, grade_3 = get_grades("{0} {1}".format(fName, lName))
average = sum([grade_1, grade_2, grade_3])/3
outfile.write("Student Name:{0} {1}\n".format(fName, lName))
outfile.write("Student ID: {0}\nUsername: {1}\n\n".format(converted_id, uName))
outfile.write("Grade 1: {0}\nGrade 2: {1}\nGrade 3: {2}\nAverage: {3}\n\n".format(grade_1, grade_2, grade_3,average))
tested with input:
sam, snead, kghasjkdfiuaski21, 2006
john, doe, 9792345678872, 2009
garth, nroken, 097892364, 2006
which outputs:
*******Student Report*******
Student Name:sam snead
Student ID: kg-ha-sjkdfiuaski21
Username: snesa2006
Grade 1: 56.0
Grade 2: 67.0
Grade 3: 78.0
Average: 67.0
Student Name:john doe
Student ID: 97-92-345678872
Username: doejo2009
Grade 1: 67.0
Grade 2: 89.0
Grade 3: 78.0
Average: 78.0
Student Name:garth nroken
Student ID: 09-78-92364
Username: nroga2006
Grade 1: 45.0
Grade 2: 67.0
Grade 3: 89.0
Average: 67.0
And remember: Eval is Evil
I am a new programming student so I'm sure it's just something I'm over looking but I keep getting the following error:
Traceback (most recent call last):
File "/Users/anonymous/Documents/sales with a list.py", line 11, in <module>
print("Sales store ") + str(count + 1) + " " + locale.currency(sales[count], grouping = True)
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
This is the code I am trying to run:
import locale
locale.setlocale(locale.LC_ALL, ' ')
sales = [0.0] * 5
totalSales = float(0.0)
for count in range(5):
sales[count] = float(input("Enter store sales amount: "))
totalSales = float(totalSales) + float(sales[count])
for count in range(5):
print("Sales store ") + str(count + 1) + " " + locale.currency(sales[count], grouping = True)
print("Total Sales of all stores " + locale.currency(totalSales, grouping = True))
You're trying to concatenate the return value of print with some strings. Try this instead:
print("Sales store " + str(count + 1) + " " + locale.currency(sales[count], grouping = True))
The difference is on the first print. In your initial code, you close the paren after "Sales store" immediately. print returns None, so your code is equivalent to:
None + str(count + 1) + " " + locale.currency(sales[count], grouping=True)
The replacement version instead builds one big string as a single argument for print.
In my Code below I am having issues with 2 things. For one The math in the function on lines 40 (examPoints) and 47 (hwkPoints) is being passed a range of values in a list on line 94. It should be taking the scores and adding them up but for some reason it isn't adding the last number on each range passed.
ex: for myValues[11:13] it is being passed the numbers 75, 95, and 97 but it only adds the first 2 and not the last.
My code is here:
from time import asctime
from time import localtime
def findGrade(myGrade): #argument number in range of 1 - 100 or float myNum?
if myGrade >= 90:
letterGrade = "A"
if myGrade >= 80:
letterGrade = "B"
if myGrade >= 70:
letterGrade = "C"
if myGrade >= 60:
letterGrade = "D"
if myGrade < 60:
letterGrade = "F"
return letterGrade
def calculatePointsEarned(hwkGrades, examGrades):
hwkTotal = float(hwkPoints(hwkGrades))
#print hwkTotal
examTotal = float(examPoints(examGrades))
#print examTotal
myAverage = (hwkTotal + examTotal) / possiblePoints
myAverage = myAverage * 100.0
#myAverage = int(myAverage)
return myAverage
def totalPoints(hwkGrades, examGrades):
hwkTotal = int(hwkPoints(hwkGrades))
examTotal = int(examPoints(examGrades))
allPoints = str((hwkTotal + examTotal))
return allPoints
#Create newtimeline using day of week, space, month, space, day, space, year, space time from asctime function
def timeMessage():
localtime()
newTimeline = asctime()
return newTimeline
def examPoints(examValues):
myGrades = 0
for grade in examValues:
myGrades = int(grade) + myGrades
#print str(myGrades) + " exam\n"
return myGrades
def hwkPoints(hwkValues):
myGrades = 0
for grade in hwkValues:
myGrades = int(grade) + myGrades
#print str(myGrades) + " hwk"
return myGrades
def requestMessage (myValues, myTime):
nameLine = myValues[1] + ", " + myValues[2] + "\t" + myValues[0] + "\t" + myValues[3]
examScore = "Exam " + "- " + myValues[11] + ", " + myValues[12] + ", " + myValues[13]
hwkScore = "Homework " + "- " + myValues[4] + ", " + myValues[5] + ", " + myValues[6] + ", " + myValues[7] + ", " + myValues[8] + ", " + myValues[9] + ", " + myValues[10]
pointsEarned = "Total points earned " + "- " + totalPoints(myValues[4:10], myValues[11:13])
myGrade = "Grade: " + str(theAverage) + " that is a " + findGrade(theAverage)
message = nameLine + "\n" + examScore + "\n" + hwkScore + "\n" + pointsEarned + "\n" + myGrade + "\n" + myTime
return message
def fileOutput(studentID, lastName, firstName, dateTime):
myLine = studentID + " " + lastName + ", " + firstName + " " + dateTime + "\n"
return myLine
#Create input stream from grades.dat and assign to infile
inFile = open('grades.dat', "r")
#Create output stream to results.dat and assign to outfile
outFile = open('results.dat', 'w+')
myTime = timeMessage()
theAverage = 0
theLettergrade = ""
theMessage = ""
possiblePoints = 550
theRequest = ""
studentID = raw_input("Please input student ID: ")
myLine = "notemptystring"
while myLine != "": #may be wrong Is myline not equal to the empty string?
myLine = inFile.readline() #may be wrong Read line from infile and assign to myline
myLine = myLine.strip('\r\n')
myValues = myLine.split(",") #Separate values in myline and assign to myvalues
if studentID == myValues[0]:
#print myValues
#Call calculatePointsEarned function with a list of homework values and a list of exam values and assign to theaverage
theAverage = calculatePointsEarned(myValues[4:10], myValues[11:13])
#print theAverage
theLettergrade = findGrade(theAverage) #Call findGrade function with theaverage and assign to thelettergrade)
#print theLettergrade
#Call fileOutput function with studentid, lastname, firstname, and datetime to get message for writing to output file, and assign to therequest
theRequest = fileOutput(myValues[0], myValues[1], myValues[2], timeMessage())
#print theRequest
theMessage = requestMessage(myValues, timeMessage()) #Call requestMessage with myline and mytime for message to display, and assign to themessage
#Write theRequest to outfile
outFile.write(theRequest)
print theMessage
else: #is studentid not equal to first element in myValues
"Do Nothing"
#close infile and outfile
inFile.close()
outFile.close()
Edit: Sorry for the link I was having problems getting the code to look right on here.
for myValues[11:13] it is being passed the numbers 75, 95, and 97 but it only adds the first 2 and not the last
myValues[11:13] selects two elements, not three. The end index (13) is not included in the range.
Have a read of Explain Python's slice notation