I have 2 functions: check_question_count() that asks a user to give an input of a number between 1 and 15 , validates the input, then returns it; random_question() function takes that returned number and generates a number of questions.
The issue is that the returned value from the first function does not seem to be returned, because i get an error that says: UnboundLocalError: local variable 'q_count' referenced before assignment.
def random_question():
check_question_count()
q_index = 1
global saved_question_count
saved_question_count = int(q_count)
print('Awesome! you will be asked ', saved_question_count,' randomly selected questions out of the total of 15 questions available.')
#Using a while loop to print out a randomly selected question:
while q_count != 0:
b = len(questions_list) - 1
rand_num = random.randint(0,b)
global selected_question
selected_question = questions_list[rand_num]
print('\n')
print(q_index,'.',selected_question)
global user_answer
user_answer = input('Your answer is: ').capitalize()
#Using a function to validate the user_answer input:
check_submitted_answers(user_answer)
questions_list.remove(selected_question)
questions_list = questions_list
q_count = q_count - 1
q_index = q_index +1
#4- Function to check the question count input and make sure its a number between 1 to 15:
def check_question_count():
global q_count
q_count = input('\nHow many questions do you like to take? You can choose a number between 1 to 15: ')
while True:
if q_count not in ['1','2','3','4','5','6','7','8','9','10','11','12','13','14','15']:
print('Error: Invalid input! Please type in only a number between 1 and 15: ')
q_count = input('\nHow many questions do you like to take? You can choose a number between 1 to 15: ')
continue
else:
return q_count
random_question()
Any help is appreciated, thanks.
There are two problems with your code. One is severe, the other is not.
The root cause of the error UnboundLocalError: local variable 'q_count' referenced before assignment is the line q_count = q_count - 1 in random_question(). This supposed to modify the variable, but that variable is supposed to be global, and thus, not writable. This makes python believe you have a local, modifiable variable q_count, and thus, all the mentions of it in the current scope must mean this local one - and when you reference it first, it is referenced before assigned.
One solution would be to just use the global version, i.e. global saved_question_count, q_count. Another one would be to remove the line q_count = q_count - 1 - but you probably need that line. A third one would be to create a new (local) variable, and initialize it with q_count.
The best solution would be (that also fixes the second problem of unnecessary global variables) is to just return the value. Others have already explained that in detail.
You are not saving the returned value in any given variable i.e instead of
check_question_count()
try:
q_count = check_question_count()
in order to save the returned value in a variable.
You should also look into the proper use of global keyword because it is being used unnecessarily here-Use of "global" keyword
Related
This question already has answers here:
Function not changing global variable
(4 answers)
Closed 1 year ago.
from random import randrange
on = ''
max_number = 0
random_number = 0
def start():
max_number = int(input('Enter max generated number: '))
random_number = randrange(max_number)
print(random_number)
on = True
start()
print(on) # returns false??
for a school project, i need to make a number guessing game. This is the start code i have. I declared "on" before the start function but the function wont change the value of the boolean to true
Right now, on is a "local" variable, only seen and used inside the scope of the function. To change the value of any variable inside and outside the function, you need to type the command global {variable}, usually at the top of a function. In your case, add this to your function:
def start():
global on <-- Right Here
max_number = int(input('Enter max generated number: '))
You can research more about global and nonlocal variables online.
Acknowledging #Samwise comment, global and nonlocal variables aren't always the best option, but I think that it's best to learn it anyway (the more you know!). He is correct, that you will likely not even need the on variable, and also that using a return statement is the best option.
This thing is hard to post code and context inside of.
#This is a menu driven multiplication game. i am attemtping to save the high
#score in a file named multiplication_game.txt...
def single_player():
in_file = open('multiplication_game.txt', 'r')
highest_times_selection = int(in_file.readline())
print('\n____now lets see how u do on the times tables____')
correct = 0
missed = 0
times_selection = int(input(
'\nPlease enter a times time table integer to practice: '))
#This simple generates the multiplation questions and checks for right or
#wrong.
for number in range(0,11):
print(times_selection, 'x' , number, '=')
user_answer=int(input('answer: '))
correct_answer = times_selection * number
if user_answer == correct_answer:
correct+=1
else:
missed+=1
#This is where if its a perfect score and a high times table than the
#previous saved score it should be opened and the new score saved in the
#text document.
if missed == 0 and times_selection > highest_times_selection :
output_file = open('multiplication_game.txt', 'w')
name = input('You have the highest Score!!\n enter your name: ')
output_file.write(str(times_selection)+ '\n')
output_file.write(name + '\n')
else:
print('you missed ', missed, 'and got', correct,'correct\n')
output_file.close()
Try to define output_file = None before any assignment of it.
Tip: before your last if-else condition.
This looks like homework, so I don't want to give you the answer but rather lead you to it.
Take a look at your if/else for your high score table, and walk through your code twice, taking a different branch (different part of the if/else) each time you reach this spot. Write down the variable names on paper as you define them, starting over with a new sheet of paper each time you walk through. If you access a variable, check it off on your list. If you try to access a variable that's not on your list, it's the same as python saying local variable referenced before assignment -- you're trying to access it before you've defined it.
Hope this helps, both in figuring out your problem and learning how to debug in the future.
I'm currently working on a small text based game, the game remembers the gamestate based on global variables, for example, goblins_dead to see if you've killed the goblins yet.
This worked pretty well, until I decided to add a save and load function. The save function works, the load function does not, and while I know why, I can't come up with an easy fix.
The way the save function currently works is this, I have a list with all the global variables we've used in the game so far. Then I have the list run through each varaiable and give a 1 if its true or a 0 if its not, at the end it prints a "seed" that consists of a list of 1s and 0s the user can input. It looks like this, in my sample test code
def game_save():
print "This will give you a seed. Write it down, or see seed.txt"
print "When you start a new game, you will be propted to give your seed. Do so to reload."
global goblins_defeated
global lucky
global princesshelp
end = "done"
load_seed =[goblins_defeated, lucky, princesshelp, end]
load_seed.reverse()
variable = load_seed.pop()
seed = []
print globals()
while end in load_seed:
if variable == True:
seed.append("1")
print "APPENEDED 1"
print load_seed
variable = load_seed.pop()
elif variable == False:
seed.append("0")
print "APPENED 0"
print load_seed
variable = load_seed.pop()
else:
print "ERROR"
break
seedstring = ' '.join(seed)
print "This is your seed %s" %seedstring
This code works, it yields a string, that matches the values in the way I want.
The issue comes when its time to load. I inverted this process, like this:
def game_load():
print "Please type your seed in here:"
global goblins_defeated
global lucky
global princesshelp
end = "done"
seedlist = [goblins_defeated, lucky, princesshelp, end]
seed = raw_input("> ")
seed_list = seed.split(" ")
seed_value = seed_list.pop()
variable_list = [end, goblins_defeated, lucky, princesshelp]
variable = variable_list.pop()
testlist = []
while end in variable_list:
if seed_value == '1':
variable = True
print variable_list
print variable
print seed_value
elif seed_value == '0':
variable = False
print variable_list
print variable
print seed_value
else:
print "ERROR ERROR FALSE LOOP RESULT"
break
if bool(seed_list) == False:
print "List is empty"
else:
seed_value = seed_list.pop()
variable = variable_list.pop()
The mistake will be obvious to more seasoned programmers, it turns out lists load what a variable points at, not the variable name, so I can't assign things in this way.
This is where I'm stumped, I could just make a long list of if statements, but that's not very elegant. Further reading suggests that a dictionary approach might be the way to solve this, but I'm unsure on how I would go about implementing a dictionary, more specifically, I'm not sure how dictionaries interact with variables, my understanding is that this is how variables are actually stored in python, but I'm not sure how to get started on accessing and storing those variables reliably, or if I could use a global dictionary to store all my variables in the game properly. Basically, I'm unsure of how to "correctly" use a dictionary to its full potential, specifically how it interacts with variables.
That's much larger than necessary. Just use string formatting to provide the save password:
print 'Your seed is {}{}{}{}'.format(goblins_defeated+0, lucky+0, princesshelp+0, end+0)
Adding 0 converts each boolean into its numeric representation. Each value is inserted into the string, replacing the {}.
Load like this:
seed = raw_input("> ")
goblins_defeated, lucky, princesshelp, end = map(bool, map(int, seed.split()))
This splits seed on whitespace, maps each element to an integer, then maps each of those integers to a boolean, then unpacks that map object into the appropriate variables.
You don't necessarily have to store these conditions as booleans at all, as 1 and 0 will evaluate similarly, with 0 for False and 1 for True. Booleans are actually a subclass of int anyway. You can even do math with them, e.g. True+True equals 2.
#Use main and a void function named randnums.
#randnums takes no arguments and return none.
#The randnums function generates 6 random integers between 1 and 9.
#The total should be printed on a new line.
#Main should call the randnums function.
import random
total=0
def main():
randnums()
def randnums():
for nums in range(6):
nums=random.randrange(1,10)
total=total+nums
print(nums,end=' ')
print("\nThe total is:",total)
main()
I keep getting:
local variable 'total' referenced before assignment
Or when total=nums it only shows the last int generated.
Can someone please explain to a beginner what I'm doing wrong?
When you assign to a variable inside a function, Python interprets it as local variable to that function. So when you do -
total=total+nums
You are actually trying to access the local variable total before defining it.
Based on your program, does not look like you need total to be a global variable, you can simply define it as 0 at the start of randnums() . Example -
def randnums():
total = 0
for nums in range(6):
You are facing problem because of variable scope.
total=total+nums
Notice that line, in your local scope, total doesn't exist but you are trying to get it's value and then add some num with it, which is the cause of your error.
If you really want to use it, use it like below:
global total
total=total+nums
So, that it recognises the global total variable.
My task is to produce a code that greets the user and asks their name storing their name as username. Then generates 2 random numbers and an operation. The question is asked to the user. After that it checks if the users answer is correct or not also adding 1 to questionsAsked. If it is correct, 1 is added to correctAnswers. If it is incorrect, the user is told so with the correct answer. The program should end after 10 questions (hence the while questionAsked > 11). The user should be given their username and how many questions they got correct.
My problem is when I run the code,it comes up with NameError: name 'questionAsked' is not defined. I'm struggling to work out how else I could define questionAsked.
Here is what I've done so far:
import random
import math
def test():
Username=input("What is your name?")
print ("Welcome"+Username+" to the Arithmetic quiz")
num1=random.randint(1, 10)
num2=random.randint(1, 10)
Ops = ['+','-','*']
Operation = random.choice(ops)
num3=int(eval(str(num1) + operation + str(num2)))
print("What is" +" "+str(num1) + operation +str (num2,"?"))
userAnswer= int(input("Your answer:"))
if userAnswer != num3:
print("Incorrect. The right answer is"+" "+(num3))
return False
else:
print("correct")
return True
correctAnswers=0
questionsAsked=0
while questionAsked > 11:
if test () == True:
questionsAnswered +=1
correctAnswers +=1
if test () == False:
questionsAnswered +=1
You have a test while questionAsked > 11 but don't use that name anywhere else in your code. You certainly never defined it. You probably wanted to test questionsAsked (with an s) instead.
There are other problems, however. The loop should continue while you have fewer than 11 questions asked, not more. You also call test() twice, you should only call it once each loop. In your loop you use questionsAnswered but never defined that either and don't increment questionsAsked; you probably meant to increment the latter:
correctAnswers=0
questionsAsked=0
while questionsAsked < 10:
if test():
correctAnswers +=1
questionsAsked +=1
Now test() is only called the once. Both your branches incremented questionsAsked, I moved that out of the tests, and now you no longer need to check if the test failed.
Since you start counting at zero, you want to test for < 10, not 11.
Instead of a while loop, you could use a for loop using the range() function:
for question_number in range(10):
if test():
correctAnswers +=1
Now the for loop takes care of counting the number of questions asked, and you no longer need to increment a variable manually.
Next, you need to move the username handling out of the test() function. You don't need to ask the user for their name each time. Ask for the name once, before the loop, so that you can access the user's name after the 10 questions:
def test():
num1=random.randint(1, 10)
num2=random.randint(1, 10)
# ... etc.
Username = input("What is your name?")
print("Welcome", Username, "to the Arithmetic quiz")
correctAnswers = 0
for question_number in range(10):
if test():
correctAnswers +=1
# print the username and correctAnswers
You need to be careful about your names in the test() function too; you define the names Ops and Operation but try to use them as ops and operation instead. That won't work, you need to use the same case everywhere to refer to those names. The Python style guide recommends you use all lowercase with underscores for local names, to distinguish them from class names (which use CamelCase, initial uppercase letters and no spaces between words).
Next problem: you are using str() with two arguments here:
print("What is" +" "+str(num1) + operation +str (num2,"?"))
That won't work; a two-argument str() call is meant for decoding bytes to a Unicode string.
Rather than use string concatenation, just pass your values to print() as separate arguments. The function will take care of converting things to strings and adds spaces between separate arguments for you:
print("What is", num1, operation, num2, "?")
Now there will be a space between num2 and the "?" but that is not that big a problem. You can use the str.format() method to create a string with placeholders where arguments to the method are filled in for you, again converting to strings automatically. This allows you to control spaces more directly:
print("What is {} {} {}?".format(num1, operation, num2))
The three arguments are placed where each {} appears, in order.
You have many discrepancies in variable names and indentation. Remember Python is case sensitive. And by the way, the condition in your while loop will cause your program not to ask any questions.
So for example, you created a list of operations called Ops and then used the random module to select an operation from ops. Python will inevitably throw an error, as ops is not actually defined. Instead, you should use Ops because that is the variable you actually declared, with a capital letter. Again, Python is case sensitive.
Likewise, Python recognizes a difference between questionAsked and questionsAsked. It's one or the other, so choose a name and be consistent.