This question already has answers here:
How can I read inputs as numbers?
(10 answers)
Closed 8 months ago.
I don't understand why the code is causing errors. For example, the error says that you can't add an integer and a string together, but I've already converted the string to an Integer. Could you help me fix it? The code is attached. Thanks.
# In this program I will collect data
# values from the user and use python built-in functions
# to display various info about the data set
# Giving user directions
print("In this programme, you can enter")
print("some numbers and it will display the")
print("minimum, maximum, range and average")
print("of the data set you entered.")
# Setup
list = []
loop = True
# Creating function for process of entering number
def enterNumber():
print()
x = input("Enter an integer: ")
y = str.isdigit(x)
if y == True:
list.append(x)
print()
print("Successfully added to list")
print()
print("Here is your list so far")
print(list)
elif y == False:
print()
print("Sorry, this is not an integer")
else:
print("Error. Kill and start again")
while loop == True:
enterNumber()
print()
print("Would you like to add another value?")
print()
a = input("Enter 1 for Yes, enter 0 for No: ")
if a == "0":
loop = False
print()
print()
print("------------------------------------------------")
print()
print("Count:", len(list))
print()
print("Minimum:", min(list))
print()
print("Maximum:", max(list))
print()
print("Range:", int(max(list)) - int(min(list)))
print()
print("Average:", int(sum(list)) / int(len(list)))
It seems like this last line is the problem.
You need to use int() function after checking if y value is True. If not you will be appending an string value always to your list:
def enterNumber():
print()
x = input("Enter an integer: ")
y = str.isdigit(x)
if y == True:
list.append(int(x)) #int(x) converts x to integer
...
The reason for the issue is that you have string values in your list, which doesn't work.
Simple test:
l = ['1', '2']
sum(l)
results in the same error.
Easiest fix is mentioned by Cardstdani.
You have not asked for it. But there is a serious issue in your code:
You should avoid at all cost to name your list list as this overwrites the built-in list() function.
# In this program I will collect data
# values from the user and use python built-in functions
# to display various info about the data set
# Giving user directions
print("In this programme, you can enter")
print("some numbers and it will display the")
print("minimum, maximum, range and average")
print("of the data set you entered.")
# Setup
list1 = []
loop = True
# Creating function for process of entering number
def enterNumber():
print()
x = input("Enter an integer: ")
y = str.isdigit(x)
if y == True:
list1.append(x)
print()
print("Successfully added to list")
print()
print("Here is your list so far")
print(list)
elif y == False:
print()
print("Sorry, this is not an integer")
else:
print("Error. Kill and start again")
while loop == True:
enterNumber()
print()
print("Would you like to add another value?")
print()
a = input("Enter 1 for Yes, enter 0 for No: ")
if a == "0":
loop = False
print()
print()
print("------------------------------------------------")
print()
print("Count:", len(list1))
print()
print("Minimum:", min(list1))
print()
print("Maximum:", max(list1))
print()
print("Range:", int(max(list1)) - int(min(list1)))
print()
list1 = list(map(int, list1))
print("Average:", sum(list1) / len(list1))
I'm using python, idle version 3.4.2
My code when it prints, print 3 scores per name but they print like this:
Maya: 3
Maya:2
Maya: 4
I was wondering if there was any way to get it to print like this in a list/dictionary so i can call upon the scores later for sorting
Maya = [3,2,4]
Here is my code.
students_names = []
import random #import module
print("What is your name?") #prints writing in brackets
name = input().title() #Capitalizes the first letter of the word inputted
students_names.append(name)
print("What class are you in? (Enter 1, 2 or 3)") #asks the user to input a number
while True:
try:
class_number = int(input()) #asks for an integer input from user
except ValueError:
print("Sorry, I didn't understand that, please try again") #print statement
continue
if class_number > 3: #if input is more than 3
print("SORRY but that class isn't recognised, try again") #print statement
continue
else:
print ("Hello,", name, "from class", class_number, "welcome to my quiz") #prints writing in brackets and anything saved in the variable "name" and "class_number"
break #break out of loop
score = 0 #sets the variable "score" to zero
question = 0 # sets the variable "question" to zero
print(class_number)
while question < 3:#If questions (intitally set to 0) is smaller than 10, carry out this function
question +=1 # add one to the value of "question"
maths = random.randint(1,3) #randomly generate a number from 1-3 and store as "maths"
num1 = random.randint(1,10)#randomly generate an integer from 1-10 and store as "num1"
num2 = random.randint(1,10)#randomly generate a second integer from 1-10 and store as "num2"
if maths == 1: #if the number generated is 1
print(num1, "+", num2) #prints num1 + num2
ans = num1 + num2 #sets "ans" to equal the value of num1 added to num2
elif maths == 2: #if the number generated is 1
print(num1, "*", num2) #print num1 multiplied by num2
ans = num1 * num2 #sets "ans" to equal the value of num1 multiplied by num2
else: #else run this part of code
print(num1, "-", num2) #print num1 subtracted by num2
ans = num1 - num2 #sets "ans" to equal the value of num1 subtracted by num2
while True:
try:
user_ans = int(input()) #user inputs answer to question
except ValueError: #runs when the user input is no an integer
print ("SORRY but that answer isn't recognised, try again")
else:
break
if user_ans == ans:
score+=1
print("Well done, you are CORRECT")
else:
print("SORRY, you are INCORRECT") #print writing in brackets
print("The correct answer was", ans)
if score == 10: #run this part of code if "score" equals 10
print("fantastic", name, "you got full marks!")#print statement and name
elif score >= 6: #run this part of code if "score" is larger than or equal to 6
print("well done, there's some improvement to be done here though", name, "you got", score, "/10")# then print statement and score
elif score <=5: #run this part of code if "score" is smaller than or equal to 5
print("hmm, maybe some more practise would be beneficial", name, "you got", score, "/10") #then print statement and score
class_number = str(class_number) + ".txt" #this adds '.txt' to the end of the file (therefore creating a text file) so it can be used to create a file under the name of the class
file = open(class_number, 'a') #opens the file in 'append' mode so you don't delete all the information
file.write(str(students_names))
file.write(str(name + " : ")) #writes the name and ":" to file
file.write(str(score)) #writes the score to file
file.write('\n')#writes the score to the file
file.close()#safely closes the file to save the information
Sure simply add the score values foreach person to a new dictionary.
name_dict = {}
if name in name_dict:
name_dict[name].append(new_score)
else:
name_dict[name] = [new_score]
It is a little bit hard to follow up on your code. Therefore I was not completely able to integrate it.
Ok, I think I get what you're looking for. But to simplify my answer to that, we first need to simplify your example. A good way to do so, is to cut your code into functions:
How to store your results?
First we'll look at where you need help on, which is the last bit of your code, which fits in a function we'll call store_results():
def store_results(...):
class_number = str(class_number) + ".txt" # this adds '.txt' to the end of the file (therefore creating a text file) so it can be used to create a file under the name of the class
file = open(class_number, 'a') # opens the file in 'append' mode so you don't delete all the information
file.write(str(students_names))
file.write(str(name + " : ")) # writes the name and ":" to file
file.write(str(score)) # writes the score to file
file.write('\n') # writes the score to the file
file.close() # safely closes the file to save the information
I used here ... for the arguments of the function, which is not python, to have a thought about it. What arguments does that function needs to work as is?
class_number: the class the student answering the QA is in
name: the score the student had on the QA
student_names
What you're doing here, is that when you run that code, you're appending name
into student_names, which will always contain one, and only one name. So when
you write file.write(str(students_names)), for a user whose name is John, you'll
end up writing:
...
['John']
John : 5
...
Which is not something I believe you're expecting. You actually do not need that list at all.
So as a first update, you should do:
def store_results(class_number, name, score):
class_file = "{}.txt".format(class_number) # this adds '.txt' to the end of the file (therefore creating a text file) so it can be used to create a file under the name of the class
with open(class_file, 'a') as f: # opens the file in 'append' mode so you don't delete all the information
f.write("{}: {}\n".format(name, score) # outputs the user's score to the file
Other changes in that snippet are:
- you shall not use file as a variable as it already exists as a global type, and using it in
your code is considered bad practice called "shadowing" which can lead to hard to find bugs
(not in this case, but if you don't take the good habits now, it's bite you in a future code).
- you shall use with open() as f: construct instead of opening and closing the file manually,
because in your existing code, if there's an exception thrown between open and close your
file won't be properly closed, ending up in possible lost writes.
- you shall use format strings instead of direct string concatenation, which makes the code
easier to read and to modify.
Now, that being said, you'll still have your issue having the result of each test taken
by an user being shown as:
John: 2
John: 4
John: 5
The right way to solve this is to not use "blinded" appending to the file, but instead
use the file as some sort of very basic database. The most simple option would be to
write your scores within a JSON file, which is syntactically compatible with python
(pretty useful for manual testing):
import os
import json
def store_results(class_number, name, score):
# this adds '.json' to the end of the file (therefore creating a json file)
class_file = "{}.json".format(class_number)
# first step: load the existing data
# first test if the file exists, and if not, use an empty score dictionary
if not os.path.exists(class_file):
scores = {}
# otherwise populate the dictionary
else:
# open as read only, because we just want the data out of it
with open(class_file, 'r') as f:
# load contents of the json file "f" as object "scores"
scores = json.load(f)
# second step: update the data
scores.setdefault(name, []).append(score)
# third step: update the file
# use 'w' when opening the file to overwrite all data within it
with open(class_file, 'w') as f:
# dump object "scores" within file "f"
json.dump(scores, f)
Within this code, I used a trick to do insertion of the score in one line:
scores.setdefault(name, []).append(score)
which is equivalent to:
# if the user's "name" is not already in the dictionary
if name not in scores.keys():
# add it as a new key containing an empty list
scores[name] = []
# append the "score" to the list indexed by the user's "name"
scores[name].append(score)
Then the results within a file would look like:
{"John":[3,5,10],"Jane":[2],"Bob":[1,0,2]}
To make the output file more readable you can change the json.dump line into:
json.dump(scores, f, sort_keys=True, indent=4, separators=(',', ': '))
which will output:
{
"Bob": [
1,
0,
2
],
"Jane": [
2
],
"John": [
3,
5,
10
]
}
How to run the QA?
Finally you want to create another function that handles the QA process, within which
you call the function we just defined
# add the following import at the start of your script if you're running python2 and not python3
from __future__ import print_function
def run_qa():
print("What is your name?") # prints writing in brackets
name = input().title() # Capitalizes the first letter of the word inputted
print("What class are you in? (Enter 1, 2 or 3)") # asks the user to input a number
while True:
try:
class_number = int(input()) # asks for an integer input from user
except ValueError:
print("Sorry, I didn't understand that, please try again") # print statement
continue
if class_number > 3: # if input is more than 3
print("SORRY but that class isn't recognised, try again") # print statement
continue
else:
break # break out of loop
# prints writing in brackets and anything saved in the variables "name" and "class_number"
print ("Hello, {} from class {} welcome to my quiz".format(name, class_number))
score = 0 # sets the variable "score" to zero
question = 0 # sets the variable "question" to zero
while question < 3: # If questions (initially set to 0) is smaller than 10, carry out this function
question += 1 # add one to the value of "question"
maths = random.randint(1,3) # randomly generate a number from 1-3 and store as "maths"
num1 = random.randint(1,10) # randomly generate an integer from 1-10 and store as "num1"
num2 = random.randint(1,10) # randomly generate a second integer from 1-10 and store as "num2"
if maths == 1: # if the number generated is 1
print("{} + {} = ?".format(num1, num2)) # prints num1 + num2
ans = num1 + num2 # sets "ans" to equal the value of num1 added to num2
elif maths == 2: # if the number generated is 1
print("{} * {} = ?".format(num1, num2)) # print num1 multiplied by num2
ans = num1 * num2 # sets "ans" to equal the value of num1 multiplied by num2
else: # else run this part of code
print("{} - {} = ?".format(num1, num2)) # print num1 subtracted by num2
ans = num1 - num2 # sets "ans" to equal the value of num1 subtracted by num2
while True:
try:
# print a nice little prompt for the user to enter his answer
print("> ", end="")
user_ans = int(input()) # user inputs answer to question
# if an exception is raised by "int()" the break is not being called
# here you achieve the same as a single line, as you're doing in two
# lines with your try/except/else clause, making your code more readable.
break
except ValueError: # runs when the user input is no an integer
print ("SORRY but that answer isn't recognised, try again")
if user_ans == ans:
score += 1
print("Well done, you are CORRECT")
else:
print("SORRY, you are INCORRECT") # print writing in brackets
print("The correct answer was {}".format(ans))
if score == 10: # run this part of code if "score" equals 10
print("Fantastic {}, you got full marks!".format(name))# print statement and name
elif score >= 6: # run this part of code if "score" is larger than or equal to 6
print("Well done, there's some improvement to be done here, though {} you got {}/10".format(name, score))# then print statement and score
elif score <=5: # run this part of code if "score" is smaller than or equal to 5
print("hmm, maybe some more practice would be beneficial, {}, you got {}/10".format(name, score)) # then print statement and score
# return the results
return class_number, name, score
Finally, to call your code, you just need to add the following at the end of your script:
if __name__ == "__main__":
class_number, name, score = run_qa()
store_results(class_number, name, score):
the reason for the if statement is to make it possible to later include your code as
a module in another module without running it, which is considered good practice!
as another improvement I'd avoid repeating the same code several times to check input
from the user, but use a function instead:
def get_integer_input(maxval=None):
while True:
try:
# print a nice prompt
print("> ", eol="")
i = int(input()) # asks for an integer input from user
if maxval:
if i >= maxval:
continue
print("Sorry, input shall be inferior than {}, try again".format(maxval))
break
except ValueError:
print("Sorry, I didn't understand that, please try again") # print statement
return i
Then in your code you use it that way:
...
class_number = get_integer_input(maxval=3)
...
BTW, as an improvement, I'd actually split the run_qa in two functions: one that
generates the questions, and the other that does the interactive process.
so that you would do:
if __name__ == "__main__":
questions = generate_qa()
class_number, name, score = run_qa(questions)
store_results(class_number, name, score)
with generate_qa() being something like:
def generate_qa():
questions = []
while len(questions) < 3: # add a question until we have three generated
op = random.randint(0,2) # randomly generate a number from 1-3 and store as "maths"
num1 = random.randint(1,10) # randomly generate an integer from 1-10 and store as "num1"
num2 = random.randint(1,10) # randomly generate a second integer from 1-10 and store as "num2"
questions.append( (op, num1, num2) )
return questions
and then:
def run_qa(questions):
print("What is your name?") # prints writing in brackets
name = input().title() # Capitalizes the first letter of the word inputted
print("What class are you in? (Enter 1, 2 or 3)") # asks the user to input a number
class_number = get_integer_input(maxval=3)
# prints writing in brackets and anything saved in the variables "name" and "class_number"
print ("Hello, {} from class {} welcome to my quiz".format(name, class_number))
score = 0 # sets the variable "score" to zero
for op, left, right in questions:
if op == 0: # if the number generated is 0
op("{} + {} = ?".format(left, right)) # prints 'left' + 'right'
ans = left + right # sets "ans" to equal the value of num1 added to 'right'
elif op == 1: # if the number generated is 1
print("{} * {} = ?".format(left, right)) # print 'left' multiplied by 'right'
ans = left * right # sets "ans" to equal the value of num1 multiplied by 'right'
else: # the only possible value is: op == 2
print("{} - {} = ?".format(left, right)) # print 'left' subtracted by 'right'
ans = left - right # sets "ans" to equal the value of num1 subtracted by 'right'
user_ans = get_integer_input()
if user_ans == ans:
score += 1
print("Well done, you are CORRECT")
else:
print("SORRY, you are INCORRECT") # print writing in brackets
print("The correct answer was {}".format(ans))
if score == 10: # run this part of code if "score" equals 10
print("Fantastic {}, you got full marks!".format(name))# print statement and name
elif score >= 6: # run this part of code if "score" is larger than or equal to 6
print("Well done, there's some improvement to be done here, though {} you got {}/10".format(name, score))# then print statement and score
elif score <=5: # run this part of code if "score" is smaller than or equal to 5
print("hmm, maybe some more practise would be beneficial, {}, you got {}/10".format(name, score)) # then print statement and score
return class_number, name, score
Finally, a last improvement that could be done to your code is to use a dict containing the operators:
import operator
operations = {
'+': operator.add,
'*': operator.mul,
'-': operator.sub
}
and then you'd simplify run_qa as follows:
def run_qa(questions):
print("What is your name?") # prints writing in brackets
name = input().title() # Capitalizes the first letter of the word inputted
print("What class are you in? (Enter 1, 2 or 3)") # asks the user to input a number
class_number = get_integer_input(maxval=3)
# prints writing in brackets and anything saved in the variables "name" and "class_number"
print ("Hello, {} from class {} welcome to my quiz".format(name, class_number))
score = 0 # sets the variable "score" to zero
for op, left, right in questions:
# convert from index value into symbol (the "list()" is a needed trick for python3
op = list(operations.keys())[op]
print("{} {} {} = ?".format(left, op, right))
# calculate the operation with operator 'op' using 'left' and 'right'
ans = operations[op](left, right)
user_ans = get_integer_input()
if user_ans == ans:
score += 1
print("Well done, you are CORRECT")
else:
print("SORRY, you are INCORRECT") # print writing in brackets
print("The correct answer was {}".format(ans))
if score == 10: # run this part of code if "score" equals 10
print("Fantastic {}, you got full marks!".format(name))# print statement and name
elif score >= 6: # run this part of code if "score" is larger than or equal to 6
print("Well done, there's some improvement to be done here, though {} you got {}/10".format(name, score))# then print statement and score
elif score <=5: # run this part of code if "score" is smaller than or equal to 5
print("hmm, maybe some more practice would be beneficial, {}, you got {}/10".format(name, score)) # then print statement and score
return class_number, name, score
Nota Bene: I have not tested my code locally, it's been live coding within the answer box
of stackoverflow, so there might be syntax errors and maybe minor bugs. The goal of
my answer is to emphasize what you're doing wrong and show you how to do better. So,
please do not take it "as is" to copy/paste, but read it through, understand what I'm
showing to you, and update your code with what I given you as an improvement.
Here's a full example I just tested:
# make the script both py2 and py3 compatible
from __future__ import print_function
import sys
if sys.version_info.major == 2:
input = raw_input
import operator
import random
import json
import os
def store_results(class_number, name, score):
# this adds '.json' to the end of the file (therefore creating a json file)
class_file = "{}.json".format(class_number)
# first step: load the existing data
# first test if the file exists, and if not, use an empty score dictionary
if not os.path.exists(class_file):
scores = {}
# otherwise populate the dictionary
else:
# open as read only, because we just want the data out of it
with open(class_file, 'r') as f:
# load contents of the json file "f" as object "scores"
scores = json.load(f)
# second step: update the data
scores.setdefault(name, []).append(score)
# third step: update the file
# use 'w' when opening the file to overwrite all data within it
with open(class_file, 'w') as f:
# dump object "scores" within file "f"
json.dump(scores, f, sort_keys=True, indent=4, separators=(',', ': '))
def get_integer_input(maxval=None):
while True:
try:
# print a nice prompt
print("> ", end="")
i = int(input()) # asks for an integer input from user
if maxval:
if i >= maxval:
continue
print("Sorry, input shall be inferior than {}, try again".format(maxval))
break
except ValueError:
print("Sorry, I didn't understand that, please try again") # print statement
return i
operations = {
'+': operator.add,
'*': operator.mul,
'-': operator.sub
}
def generate_qa():
questions = []
while len(questions) < 3: # add a question until we have three generated
op = random.randint(0,2) # randomly generate a number from 1-3 and store as "maths"
num1 = random.randint(1,10) # randomly generate an integer from 1-10 and store as "num1"
num2 = random.randint(1,10) # randomly generate a second integer from 1-10 and store as "num2"
questions.append( (op, num1, num2) )
return questions
def run_qa(questions):
print("What is your name?") # prints writing in brackets
name = input().title() # Capitalizes the first letter of the word inputted
print("What class are you in? (Enter 1, 2 or 3)") # asks the user to input a number
class_number = get_integer_input(maxval=3)
# prints writing in brackets and anything saved in the variables "name" and "class_number"
print ("Hello, {} from class {} welcome to my quiz".format(name, class_number))
score = 0 # sets the variable "score" to zero
for op, left, right in questions:
# convert from index value into symbol (the "list()" is a needed trick for python3
op = list(operations.keys())[op]
print("{} {} {} = ?".format(left, op, right))
# calculate the operation with operator 'op' using 'left' and 'right'
ans = operations[op](left, right)
user_ans = get_integer_input()
if user_ans == ans:
score += 1
print("Well done, you are CORRECT")
else:
print("SORRY, you are INCORRECT") # print writing in brackets
print("The correct answer was {}".format(ans))
if score == 10: # run this part of code if "score" equals 10
print("Fantastic {}, you got full marks!".format(name))# print statement and name
elif score >= 6: # run this part of code if "score" is larger than or equal to 6
print("Well done, there's some improvement to be done here, though {} you got {}/10".format(name, score))# then print statement and score
elif score <=5: # run this part of code if "score" is smaller than or equal to 5
print("hmm, maybe some more practise would be beneficial, {}, you got {}/10".format(name, score)) # then print statement and score
return class_number, name, score
if __name__ == "__main__":
questions = generate_qa()
class_number, name, score = run_qa(questions)
store_results(class_number, name, score)
HTH