Having problems passing info from one function to another (Python) - python

I'm fairly new to python (been taking classes for a few months) and I've come across a reoccurring problem with my code involving passing information, such as an integer, from one function to another. In this case, I'm having problems with passing "totalPints" from "def getTotal" to "def averagePints" (totalPints in def averagePints defaults to 0).
def main():
endQuery = "n"
while endQuery == "n":
pints = [0] * 7
totalPints = 0
avgPints = 0
option = ""
print("Welcome to the American Red Cross blood drive database.")
print()
print("Please enter 'w' to write new data to the file. Enter 'r' to read data currently on file. Enter 'e' to "
"end the program.")
try:
option = input("Enter w/r/e: ")
except ValueError:
print()
print("Please input only w/r/e")
if option == "w":
print()
def getPints(pints):
index = 0
while index < 7:
pints[index] = input("Input number of Pints of Blood donated for day " + str(index + 1) + ": ")
print(pints)
index = index + 1
getPints(pints)
def getTotal(pints, totalPints):
index = 0
while index < 7:
totalPints = totalPints + int(pints[index])
index = index + 1
print(totalPints)
getTotal(pints, totalPints)
def averagePints(totalPints, avgPints):
avgPints = float(totalPints) / 7
print(avgPints)
averagePints(totalPints, avgPints)
Passing information from "def getPints" to "def getTotal" works fine, and both print the accurate information, but nothing passes from "def getTotal" to "def averagePints" and returns 0. What am I doing wrong in this case? Is it something to do with the scope of the variables listed above?
This is my first time posting to Stack Overflow because I could find any fixes to what I am having troubles with. What I expect to happen from this code is passing the number from "totalPints" in "def getTotal" to "def averagePints" to make a calculation with that number. I tried messing with the scopes of the declared variables and the order of when functions are called but I still can't really tell what I'm missing. All I know is that the value of "totalPints" in "def averagePints" always returns 0.

You have a variable scoping issue. In getTotal, totalPints is being updated with its value local to the function, not the global one like you are expecting. Returning the new value from the function and assigning it seems to have the intended effect. Below is the updated snippet:
def getTotal(pints, totalPints):
index = 0
while index < 7:
totalPints = totalPints + int(pints[index])
index = index + 1
print(totalPints)
return totalPints
totalPints = getTotal(pints, totalPints)

Related

why doesn't += work in a while true loop python?

the code just doesn't work, I can not understand what is wrong with the +=
taken = 1
first = int(input(" "))
while taken <= 6:
print(1)
print(taken+=1)
the syntax error just pops up and the + is highlighted red, I have tried looking however the only question I found was where it did not work because of the global the person put before the thing they were += onto.
This is because variable += val is shorthand for
variable = variable + val
As this is an assignment expression, and doesn't return anything, that's why this is considered to be a syntax error.
Note 1: This has nothing to do with while loop, it's universally unaccepted
Note 2: Python doesn't support ++ / -- operators as of now
So, do this instead:
taken = 1
first = int(input(" "))
while taken <= 6:
taken+=1
print(f"1\n{taken}")
Try to write taken += 1 in the row above and than print taken.
taken = 1
first = int(input(" "))
while taken <= 6:
print(1)
taken += 1
print(taken)
you simply cannot do that.
you can do this instead :
taken = 1
first = int(input(" "))
while taken <= 6:
print(1)
taken += 1
print(taken)

The function does not redirect the user to the next question

I have already tried many times to fix this problem, but I can not solve it in any way. I use an index as a variable to move the user to the next question, but after correct and incorrect answers, the index remains at 0.
score = 0
index = 0
num = 0
user_answer = ""
correct = ""
#------------------------------------------------------------------------------
question_list = ["What is this shape? \na. Square \nb. Triangle \nc. Oval \nAnswer: ", "What color is this shape? \na. Blue \nb. Red \nc. Orange \nAnswer: "]
answer_list = ["a", "c"]
def AnswerCheck (num):
global user_answer, correct, index, score
while (correct == "false"):
user_answer = input(question_list[num])
if (user_answer == answer_list[num]):
score += 1
print("Correct!")
print("Score:", score)
print("\n")
else:
print("Incorrect!")
print("Score:", score)
print("\n")
index = index + 1
while index < len(question_list):
correct = "false"
AnswerCheck(index)
So the reason why the index isn't moving is that you are not letting it execute. first things first, you need to define the variables outside of the functions then make a function called main. main will be the driver function that you will be using to execute the rest of the code. the next step is to place the index += 1 outside of the while loop, then and a return call at the end of the function to push the results back to main. finally, you need to stop the while loop that is asking the question, to do this add break. this will stop the while loop from executing if the correct answer is entered.
question_list = ["What is this shape? \na. Square \nb. Triangle \nc. Oval \nAnswer: ", "What color is this shape? \na. Blue \nb. Red \nc. Orange \nAnswer: "]
answer_list = ["a", "c"]
user_answer = ""
correct = "false"
index = 0
score = 0
def AnswerCheck (num):
global index, score, user_answer, correct
while (correct == "false"):
user_answer = input(question_list[num])
if (user_answer == answer_list[num]):
score += 1
print("Correct!")
print("Score:", score)
print("\n")
break
else:
print("Incorrect!")
print("Score:", score)
print("\n")
index = index + 1
return
def main():
while index < len(question_list):
correct = "false"
AnswerCheck(index)
main()
This code ran fine on my side let me know if you have any questions.
You have this condition while (correct == "false"), correct variable has the value "false" from the start, and you don't change correct value anywhere in the body of your loop. Hence you will never exit the loop.
And about index remaining always zero. It's not true. You can print the value of index before user_answer = input(question_list[num]) and you will see that it has changed.
The problem is that you are passing the index as an argument here AnswerCheck(index). Because int is a primitive type in Python the value of the index variable will be copied and stored in the num variable inside your AnswerCheck function.
Because of that, num in AnswerCheck and index from the outside scope are not connected in any way. That means changing index will not change the value of num and vice versa.
And you will never exit AnswerCheck as I mentioned in the beginning, so your num variable will never change, and you stuck with the num being 0.
There are a lot of ways to solve it. The most simple ones are changing your while condition or updating the num variable, depending on the desired results.
Also, consider avoiding using global it's not the best practice and can lead to some difficulties debugging. You can read more reasoning about it.

What is wrong with my Python program using the find command?

I am trying to type in a list of names and then determine which ones contain the letter "e" or the letter "E" but it always just returns as 0. Can somebody tell me why?
def count_contain_e():
num_names = int(input("How many names are you going to enter: "))
count = 0
for i in range(num_names):
name = input("Enter middle name: ")
if (name.find("e") >= 0):
count += 1
return count
def main():
num_w_e = count_contain_e()
print "The number of middle names with the letter e is " + str(num_w_e)
main()
You have a problem with indentation. The if should be on the same level as name assignment (1 more tab than currently).
The problem is the identation of if statement.
What you need is insert the if inside the for in order to analyze all the names that you input, like this:
for i in range(num_names):
name = input("Enter middle name: ")
if (name.find("e") >= 0):
count += 1
Right now in the if you are only analyzing the last name because in the loop you are rewriting the variable all the time before to do the find method.
And for sure, if you want to count the capital letter too, you need to add it to the if condition, if not the program only counts the lower letter.

can't see a way around global var

I am just learning to script python working my way thru MIT comp. science open course and I have a question. I have read that setting vars to global inside of functions is the root of, well at least some evil. Although I am sure there is an obvious answer to my question, I could not see a way around NOT setting a global var in my func 'rand_guess' because I need the values from the func in the main body's while loop to perform further processing. I hope then someone might describe a more acceptable (pythonic I think is the term) way I could do so. Here is my script:
# Instruct the user to pick an arbitrary number from 1 to 100 and proceed to
# guess it correctly within 10 attempts. After each guess, the user must tell
# whether their number is higher than, lower than, or equal to your guess.
def rand_guess(l, h):
# print "l: " + str(l)
# print "h: " + str(h)
# global rand_num
rand_num = random.randint(l, h)
print(str(cntr) + '_2: ' + str(rand_num)) # debug
if rand_num != user_num:
if cntr < attempts:
print '\nMy guess of ' + str(rand_num) + ' is wrong.'
# global hi_lo
hi_lo = raw_input('So should my next guess be [H]igher or [L]ower? ')
print(str(cntr) + '_2: ' + hi_lo) # debug
else:
print '\nMy guess of ' + str(rand_num) + \
' is wrong, and I am out of guesses.\n'
exit()
else:
print '\nWoW! I can hardly believe it! My guess is correct: ' + \
str(user_num) + '\n'
exit()
return rand_num
return hi_lo
import random
attempts = 5
rand_num = 1
hi_lo = ''
lo = 1
hi = 100
user_num = int(raw_input('\nEnter a number between 1 to 100: '))
cntr = 1
while cntr < (attempts+1):
# first guess will be a random num between 1 to 100 so first lo_num must be
print(str(cntr) + '_1: ' + hi_lo) # debug
print(str(cntr) + '_1: ' + str(rand_num)) # debug
# 1
if cntr == 1:
rand_guess(lo, hi)
else:
# if user indicated to guess Higher with next guess
print(str(cntr) + '_3: ' + hi_lo) # debug
if hi_lo == 'H':
# then last number guessed +1 should be the lowest number guessed
# for all future guesses
print(str(cntr) + '_3: ' + str(rand_num)) # debug
if rand_num > lo:
lo = rand_num + 1
# user indicated to guess Lower with next guess
else:
# then last number guessed -1 should be the highest number guessed
# for all future guesses
if rand_num < hi:
hi = rand_num - 1
# func call with new lo-hi guess brackets
rand_guess(lo, hi)
cntr += 1
In addition, I would appreciate reading any others constructive suggestions regarding obvious python formatting faux pas I might be making, as I realize format in python is of the utmost importance.
EDIT:
Ok so I replaced the global statements with return statements, like what I originally tried and still the values I expect to be returned seem to be causing me problems. I added in some additional print statements to try to help determine what value a given var is at different points in the code. Here is the output of this script, including python debug details:
Enter a number between 1 to 100: 50
1_1:
1_1: 1
1_2: 61
My guess of 61 is wrong.
So should my next guess be [H]igher or [L]ower? L
1_2: L
2_1:
2_1: 1
2_3:
Traceback (most recent call last):
File "ex_loops2.py", line 67, in <module>
rand_guess(lo, hi)
File "ex_loops2.py", line 10, in rand_guess
rand_num = random.randint(l, h)
File "/usr/lib/python2.7/random.py", line 241, in randint
return self.randrange(a, b+1)
File "/usr/lib/python2.7/random.py", line 217, in randrange
raise ValueError, "empty range for randrange() (%d,%d, %d)" % (istart, istop, width)
ValueError: empty range for randrange() (1,1, 0)
02:53 exercises $
The first empty value for print '2_1: ' should have been 'H' (in this instance) and the value '1' for the second `print' '2_1: 1' right before pythons throws its error I expected to be '2_1: 61' (again for this particular instance, the returned value of 'rand_num').
So again, if I simply global those vars the script works as expected. I am sure someone can point out my obvious oversight or omission or wrong assumption and use of python's return statement here, because I am stumped.
While I can see how Justin's modified example below is a much better revision of what I am trying to accomplish here, I really just to need to know what it is I am doing wrong trying to return these particular var values so they are available outside of the func in which they are assigned (since the script basically works otherwise). I think remaining in the context I am having problems will yield the greatest benefit regarding this basic aspect of python.
This isn't exactly what you are looking for, but it should give some pointers.
import sys
import random
def random_guess(low=1, high=100, attempts=10, hints=True):
"""Try to guess the random number.
Args:
low (int): Lowest number the value can be.
high (int): Highest number the value can be.
attempts (int): How many tries you get.
hints (bool): Change range boundaries.
"""
# Command line args come in as strings.
low = int(low)
high = int(high)
attempts = int(attempts)
hints = hints in [True, 1, "True", 'true', '1', 't', 'y', 'yes']
mynum = None
rand_num = random.randint(low, high)
for _ in range(attempts): # _ means the last command ... i isn't used. Skips the pylint warning
# Check input
if hints and mynum is not None:
if mynum < rand_num:
low = mynum + 1
print("Incorrect answer! Guess higher next time")
elif mynum > rand_num:
high = mynum - 1
print("Incorrect answer! Guess lower next time")
elif mynum is not None:
print("Incorrect answer!", end=" ")
# Ask the user for input (raw_input for python 2.x)
try:
mynum = int(input('Enter a number between '+str(low)+' to '+str(high)+': '))
if mynum == rand_num:
print("Congratulations, you win!")
return # skip the print you lose and exit the function
except ValueError:
print("That wasn't a number.")
# end for
print("Sorry you lose!")
# end main
# Use name to check if it is the main. This prevents the below code from executing on import.
# So another application and import the random_guess method and use it without actually running it.
if __name__ == "__main__":
commandline_args = sys.argv[1:] # First argument is usually the filename
random_guess(*commandline_args) # run the main method

PYTHON: Error Message in random.py? Used to work, then it didn't, then it did, now it doesn't again. What's happening?

I've been learning python for a few months now, and usually I've been able to overcome all the problems I face, but now I'm at a loss. I'm writing a program called 'Quizzer' that will be used to generate random questions based on lists of terms and answers that Python is given.
My main problem has with the the gen_question function I've been working on. I wanted Python to receive a term, and output four multiple choice answers: One the actual, and three randomly selected from the pool of all possible answers. I had to include several checks to make sure the selected random answers were not the real answer and were not the same as each other.
I finally got it to work today, and then a bit later I tested it. I got an error message (that I will display in a second). I undid everything back to where I was earlier and I still got the same error message. After a few hours I came back, and I got it again. Out of frustration, I retried, and it worked. Now it isn't working anymore. Please, anyone: What is going on?
Here is my code (I don't know what's necessary so I am including the entire thing):
#import random for generating
import random
#term and definition libraries
terms_ans ={'term1':'answer1','term2':'answer2','term3':'answer3','term4':'answer4','term5':'answer5','term6':'answer6','term7':'answer7','term8':'answer8','term9':'answer9','term10':'answer10','term11':'answer11','term12':'answer12','term13':'answer13','term14':'answer14','term15':'answer15','term16':'answer16','term17':'answer17','term18':'answer18','term19':'answer19','term20':'answer20'}
term_list = ['term1','term2','term3','term4','term5','term6','term7','term8','term9','term10','term11','term12','term13','term14','term15','term16','term17','term18','term19','term20']
answer_list = ['answer1','answer2','answer3','answer4','answer5','answer6','answer7','answer8','answer9','answer10','answer11','answer12','answer13','answer14','answer15','answer16','answer17','answer18','answer19','answer20']
#picks the test questions to ask
def gen_test(amount=len(term_list)):
found_starter = False
test_terms = []
while found_starter == False:
#pick a random starting point in the terms to see if it is suitable
start_point = random.randint(1, len(term_list))
if amount == len(term_list):
#if user inputs max amount of questions possible, just take the term list
test_terms = term_list
found_starter = True
elif len(term_list) - (start_point + amount) >= 0:
#if it is suitable, then append the terms to the test questions
for x in xrange(start_point,start_point+amount):
test_terms.append(term_list[x])
found_starter = True
else:
return test_terms
#scramble list
def list_scrambler(unscrambled_list):
test_terms=[]
countdown = len(unscrambled_list) + 1
for x in range(1, countdown):
transfer_var = random.randint(0,len(unscrambled_list)-1)
test_terms.append(unscrambled_list[transfer_var])
del unscrambled_list[transfer_var]
return test_terms
#ask user for amount of questions needed and get the list
test_terms = list_scrambler(gen_test(int(raw_input("How many questions on your test? (There are " + str(len(term_list)) + " questions in total.) "))))
def gen_question(picked_term, question_num=1, total_amount=len(test_terms)):
#print start of question
print
print "Question " + str(question_num) + " of " + str(total_amount) + ":"
print
print picked_term
print
#gather random multiple choice answers they must a) all be different and b) not be the answer
ans_1_acceptable = False
while ans_1_acceptable == False:
int_rand_ans_1 = random.randint(1, len(term_list)) - 1
if str(term_list[int_rand_ans_1]) != str(picked_term):
#Term accepted; send to output
ans_1_acceptable = True
ans_2_acceptable = False
while ans_2_acceptable == False:
int_rand_ans_2 = random.randint(1, len(term_list)) - 1
if int_rand_ans_2 != int_rand_ans_1 and str(term_list[int_rand_ans_2]) != str(picked_term):
ans_2_acceptable = True
ans_3_acceptable = False
while ans_3_acceptable == False:
int_rand_ans_3 = random.randint(1, len(term_list)) - 1
if int_rand_ans_3 != int_rand_ans_1 and int_rand_ans_3 != int_rand_ans_2 and str(term_list[int_rand_ans_3]) != str(picked_term):
ans_3_acceptable = True
#Decide if the correct answer is A, B, C, or D
correct_ans = random.randint(1,4)
#Print the options using the variables gathered above
if correct_ans != 1:
print "A) " + answer_list[int_rand_ans_1]
else:
print "A) " + terms_ans[picked_term]
if correct_ans != 2:
print "B) " + answer_list[int_rand_ans_2]
else:
print "B) " + terms_ans[picked_term]
if correct_ans != 3:
print "C) " + answer_list[int_rand_ans_3]
else:
print "C) " + terms_ans[picked_term]
if correct_ans == 1:
print "D) " + answer_list[int_rand_ans_1]
elif correct_ans == 2:
print "D) " + answer_list[int_rand_ans_2]
elif correct_ans == 3:
print "D) " + answer_list[int_rand_ans_3]
else:
print "D) " + terms_ans[picked_term]
print
Now, usually it outputs everything like you'd expect. I don't have a feature to automatically generate questions yet so I have to type in the line:
gen_question('term1')
or whatever term I'm using.
Here is the output I've been getting:
How many questions on your test? (There are 20 questions in total.) 20
>>> gen_question('term1')
Question 1 of 20:
term1
Traceback (most recent call last):
File "<pyshell#0>", line 1, in <module>
gen_question('term1')
File "C:\Users\Owner\Desktop\LEARNING PYTHON\scripts\in progress\Quizzer.py", line 69, in gen_question
int_rand_ans_1 = random.randint(1, len(term_list)) - 1
File "C:\Users\Owner\Desktop\LEARNING PYTHON\python 2.7.5\lib\random.py", line 241, in randint
return self.randrange(a, b+1)
File "C:\Users\Owner\Desktop\LEARNING PYTHON\python 2.7.5\lib\random.py", line 217, in randrange
raise ValueError, "empty range for randrange() (%d,%d, %d)" % (istart, istop, width)
ValueError: empty range for randrange() (1,1, 0)
>>> gen_question('term8')
This is what is getting you:
term_list = [...]
is defined at the start of your file, but later on you do the following when the amount entered is the max.
test_term = term_list
This does not create a copy of your array, this creates two variables which both reference the same array. So any further modifications to test_term are actually reflected against the list referenced by both variables.
And since you are defining test_terms at a global level in the script you NUKE it when you make this call
def list_scrambler(unscrambled_list):
test_terms=[]
countdown = len(unscrambled_list) + 1
for x in range(1, countdown):
transfer_var = random.randint(0,len(unscrambled_list)-1)
test_terms.append(unscrambled_list[transfer_var])
del unscrambled_list[transfer_var]
return test_terms
Also to add,
Hungarian notation is a big no-no and python is a strongly typed language anyways. If you are having a hard time keeping track of times don't rely on variable names. Instead get yourself an IDE or use names expressive of what they are doing.
if something == false:
should be rewritten as
if not something
This one is more for preference, but when printing out text that needs to have data floated in, you can save yourself some headache and write
"D) {0}".format(somelist[index])
This will stuff the variable into the {0} and provides you with some formatting context and prevents you from having to str() an object.
Also, globals in general are considered a bad thing, they're debatable. like globals in C sometimes they serve a clear purpose, but for the most part they hide bugs and make issues harder to track. Also sometimes your variable declarations will shadow globals, others (as you saw) will let you screw things up.
Well, it's pretty obvious that randint() is complaining because term_list is empty, right? Then
random.randint(1, len(term_list))
is
random.randint(1, 0)
and randint is stuck. So why is term_list empty? It's because this statement:
test_terms = list_scrambler(gen_test(int(raw_input("How many questions on your test? (There are " + str(len(term_list)) + " questions in total.) "))))
destroys term_list, and that's probably ;-) not intended.
It's hard to follow the code to track down why that happens. The basic problem is that gen_test can set
test_terms = term_list
and then end up returning term_list under the name test_terms. Then term_list is still intact at the start of list_scrambler, but empty by the time list_scrambler ends. The
del unscrambled_list[transfer_var]
deletes all the elements in term_list, one at a time.

Categories

Resources