I just started my first programming class a few weeks ago and I'm embarrassed to say I'm very stuck. We had to create a program that (in my Professor's words):
Simulate the roll of two dice. Use a randomly generated integer to represent the roll of each die in a function named point. Return the combined value of a roll. Use a loop in main to roll the dice five times and report each result.
So, I did my best and keep getting the same issue where it is telling me my variable total is not defined, even though I'm calling the function which contains the variable.
I submitted the below code to my professor, who in turn responded:
The dice program is close. Return the total of a roll. Call point in main and capture the returned value for printing.
So he is saying to call the function point in my main function (which, at least I think, I am) but it still won't read my vital variable to finishing this.
import random
min=1
max=6
def main():
for roll in range(5):
point()
print(total)
def point():
roll=random.randint(min, max)
roll2=random.randint(min, max)
total=roll+roll2
return total
main()
Inside the main function, this line:
point()
does not make total available in the current scope. Instead, it simply calls the function point and then discards its return value.
You need to capture this return value by assigning it to a variable named total:
def main():
for roll in range(5):
################
total = point()
################
print(total)
Now, when you do print(total), total will be defined and equal to the value of point().
You're trying to reference a variable that only exists within the scope of the point() function. But you don't need to since you return the value anyway.
Try this.
from random import randint
def rollD6():
return randint(1,6)
def point():
return rollD6()+rollD6()
def main():
for roll in range(5):
print point()
main()
Related
in this code there are two Random Number Generators. One in the first line, the other in the function btn_yes.
Both RNG's work fine, the print(nb) directly after the generator in the function btn_yes displays a random number like it should.
However, when btn_press is activated after btn_yes was activated (like it should in the program), the value of nb doesn't change, no matter how often i execute btn_yes. btn_press just uses the same number that was generated by the first RNG.
What am I missing?
nb = random.randrange(0, 11)
def btn_press():
guess = int(entry.get())
print(guess)
if guess < nb:
answ["text"] = "Higher!"
elif guess > nb:
answ["text"] = "Lower!"
elif guess == nb:
answ["text"] = "Correct!"
btn2["bg"] = "#FF6C6C"
btn3["bg"] = "#32FF00"
def btn_no():
window.destroy()
def btn_yes():
answ["text"] = "Next Round! Type in a new number!"
btn2["bg"] = "#464646"
btn3["bg"] = "#464646"
nb = random.randrange(0, 11)
entry.delete(0, tk.END)
print(nb)
The problem here is that when you change a global variable inside a function, you need to put global <variablename> as the first line in the function. Otherwise, Python assumes you meant to make a new variable with that name that is only in scope inside the function, and the global variable remains unchanged.
You can see this by printing nb inside the function btn_yes(); you should see that it has a different value each time (and not the same value as the global nb).
In this case, if you put global nb as the first line in btn_yes(), it should have the desired effect.
See using global variables in a function
I have a function score0 which gives me a score for every turn (for n turns) in a loop. This score is incremented by a random integer from 1 to 15 every turn.
I now have to design another higher order function which should print the highest score jump of a player out of all the score jumps yet, and should be called inside the score0 function. I name it highest_gain. Naturally, this should print the first score value as it's the first turn (hence it is the biggest jump).
# Function that defines the highest point jump in a score yet
import random
def highest_gain(previous_value, highest_point):
def say(score) :
if previous_value == 0:
print ('Biggest gain by player0 yet with',score,'points!')
return highest_gain(score, score)
gain = score - previous_value
if gain > highest_point:
print('Biggest gain by player0 yet with',score,'points!')
return highest_gain(score, gain)
return say
# Function that gives me a new score (incremented) every turn
def score0(n, score = 0):
while n > 0:
score += random.randint(1, 15)
highest_gain(previous_value = 0,highest_point = 0)(score)
n -= 1
return score
#Calling the function
score0(4,0)
Python Tutor link
The problem is that calling highest_gain() doesn't update the values of previous_value and highest_point. Why aren't these variables getting updated in the score0() function body, and how should highest_gain() be called be called so that these variables are updated on each iteration of the loop?
Your highest_gain function is a higher-order function which returns another function named say. When say is called, it calls highest_gain again and returns the result, which is - again - the function say. The important point here is that say is a closure over the local variables of the outer function highest_gain, so each time highest_gain is called you get a different instance of the say function, with different values of the outer function's local variables.
Now, since calling say returns another instance of say which closes over the updated values, that means you need to keep the result from when you call it, so you can call the new instance which closes over those updated values.
def score0(n, score=0):
say = highest_gain(previous_value=0, highest_point=0)
while n > 0:
score += random.randint(1, 15)
say = say(score) or say
n -= 1
return score
I moved the original call of highest_gain to before the loop, since you don't want to use the initial values of 0 on every iteration.
Note that say doesn't always return a new instance of say - sometimes it returns None, so I used the trick say(score) or say here so that say keeps its old value if there isn't a new one to update it with. You could alternatively write this as below, which is more verbose but perhaps makes clearer what this is doing:
new_say = say(score)
if new_say is not None:
say = new_say
Otherwise, you could change the definition of say so that it returns itself (i.e. with the current values of the variables from the outer function) when there should be no update, and then in score0 you could just write say = say(score).
I was working on building a randomized character generator for Pathfinder 3.5 and got stuck.
I am using the Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill): function to populate a randiomized list of skills with their class based points total, class bonus, and point buy. So modelling the action of a player picking skills for their character.
As an example below, Wizards.
I pick Knowledge_Arcana as a skill and spend one of my skill point pool (Calculated by taking my intelligence modifier +2) on it. So that skill now equals my intelligence modifier(+1 in this case), class skill bonus as a wizard (+3), plus the point I spent(+1) for a total of 5.
The problem is while the function prints the correct result of 5, the outstanding variables do not populate with the final total. To continue our example I'd run the function on Knowledge_Arcana, get a +5, and then check the Knowledge_Arcana after the function call and get just +1. Conversely, if I write out the function as just an if statement it works. Example is next to the function for comparison.
Does anyone know why Im getting the different result?
## Creating the lists and breaking into two separate sections
Int_Mod = 1
Skill_Ranks = 3
Rand_Class = 'Wizard'
Knowledge_Arcana = Int_Mod
Knowledge_Dungeoneering = Int_Mod
Wizard_Class_Top_Skills = ["Knowledge_Arcana"]
Wizard_Class_Less_Skills = ["Knowledge_Dungeoneering"]
Class_Skill = 3
Important_Skills_Weighted = .6
Less_Important_Skills_Weighted = .4
Important_Skills_Total_Weighted = round(Skill_Ranks*Important_Skills_Weighted)
Less_Skill_Total_Weighted = round(Skill_Ranks*Less_Important_Skills_Weighted)
Wiz_Draw =['Knowledge_Arcana', 'Knowledge_Dungeoneering']
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
## Function Calls
Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
Populate_Skills('Knowledge_Dungeoneering', Wiz_Draw, Knowledge_Dungeoneering, Class_Skill)
print(Knowledge_Arcana,Knowledge_Dungeoneering)
Edited to be a MRE, I believe. Sorry folks, Im new.
You are passing in a reference to a list and expect the function to modify it; but you are reassigning the variable inside the function which creates a local variable, which is then lost when the function is exited. You want to manipulate the same variable which the caller passed in, instead.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List.extend(Class_Skill + Draw.count(Skill_String))
print(Skill_String, Skill_List)
else:
print('Nuts!')
Alternatively, have the function return the new value, and mandate for the caller to pick it up and assign it to the variable.
def Populate_Skills(Skill_String, Draw, Skill_List, Class_Skill):
if Skill_String in Draw:
Skill_List = Skill_List + Class_Skill + Draw.count(Skill_String)
print(Skill_String, Skill_List)
else:
print('Nuts!')
return Skill_List
Skill_List = Populate_Skills('Knowledge_Arcana', Wiz_Draw, Knowledge_Arcana, Class_Skill)
# etc
You should probably also rename your variables (capital letters should be used for classes and globals; regular Python functions and variables should use snake_case) and avoid using global variables at all. The entire program looks like you should probably look into refactoring it into objects, but that's far beyond the scope of what you are asking.
Thanks firstly for bearing with me as a relative newcomer to the world of Python. I'm working on a simple set of code and have been racking my brain to understand where I am going wrong. I suspect it is a relatively simple thing to correct but all searches so far have been fruitless. If this has been covered before then please be gentle, I have looked for a couple of days!
I'm working on the following and after catching and correcting a number of issues I suspect that I'm on the last hurdle:-
def main():
our_list = []
ne = int(input('How many numbers do you wish to enter? '))
for i in range(0, (ne)): # set up loop to run user specified number of time
number=int(input('Choose a number:- '))
our_list.append(number) # append to our_list
print ('The list of numbers you have entered is ')
print (our_list)
main()
while True:
op = input ('For the mean type <1>, for the median type <2>, for the mode type <3>, to enter a new set of numbers type <4> or 5 to exit')
import statistics
if op == "1":
mn = statistics.mean(our_list)
print ("The mean of the values you have entered is:- ",mn)
if op == "2":
me = statistics.median(our_list)
print ("The median of the values you have entered is:- ",me)
if op == "3":
mo = statistics.mode(our_list)
print ("The mode of the values you have entered is:- ",mo)
if op == "5":
main()
else:
print("Goodbye")
break`
For some reason the appended (our_list) is not being recognised within the while true loop rendering the statistics calculation void. Any steer would be really appreciated as to where I am missing the obvious, thanks in advance.
Cheers
Bryan
I'm not sure exactly what you mean by "not being recognized", but our_list is a local variable inside main, so it can't be used anywhere but inside main.
So, if you try to use it elsewhere, you should get a NameError.
If your code actually has a global variable with the same name as the local variable that we aren't seeing here, things can be more confusing—you won't get a NameError, you'll get the value of the global variable, which isn't what you want.
The best solution here is to return the value from the function, and then have the caller use the returned value. For example:
def main():
our_list = []
ne = int(input('How many numbers do you wish to enter? '))
for i in range(0, (ne)): # set up loop to run user specified number of time
number=int(input('Choose a number:- '))
our_list.append(number) # append to our_list
print ('The list of numbers you have entered is ')
print (our_list)
return our_list
the_list = main()
while True:
op = input ('For the mean type <1>, for the median type <2>, for the mode type <3>, to enter a new set of numbers type <4> or 5 to exit')
import statistics
if op == "1":
mn = statistics.mean(the_list)
print ("The mean of the values you have entered is:- ",mn)
if op == "2":
me = statistics.median(the_list)
print ("The median of the values you have entered is:- ",me)
if op == "3":
mo = statistics.mode(the_list)
print ("The mode of the values you have entered is:- ",mo)
if op == "5":
the_list = main()
else:
print("Goodbye")
break
There are other options—you could pass in an empty list for main to fill, or use a global variable (or, better, a more restricted equivalent like an attribute on a class instance or a closure variable), or refactor your code so everyone who needs to access our_list is inside the same function… but I think this is the cleanest way to do what you're trying to do here.
By the way, this isn't quite the last hurdle—but you're very close:
After any mean, median, or mode, it's going to hit the "Goodbye" and exit instead of going back through the loop. Do you know about elif?
You mixed up '5' and '4' in the menu.
If the user enters 2 and 3 and asks for the mode, your code will dump a ValueError traceback to the screen; probably not what you want. Do you know try/except?
That's all I noticed, and they're all pretty simple things to add, so congrats in advance.
The issue is that our_list was defined in the main() function, and is not visible outside of the main() function scope.
Since you're doing everything in one chunk, you could remove line 1 and 6, taking the code from your main() function and putting it on the same indentation level as the code which follows.
This seems to be because you defined our_list within the main() function. You should probably define it as a global variable by creating it outside the main() function.
You could also put the while loop inside a function and pass in our_list as a parameter to the list.
I am trying to figure out how to pass arguments in Python and why my code is not working. Why is it saying that the arguments are not defined? I need the arguments in from each function to be able to speak to one another. I could only solve this problem by putting the variables in the defined main function, which is not how I wanted to design the program.
#make computer program that takes amount of doughnuts that customer
#wants to order.
#second, multiply the number of doughnuts the customer wants to order
#by the price and the sales tax.
#next, print the price of the doughnut with the sales tax
DOUGHNUT=1.75
SALES_TAX=0.08625
def getNumDoughnuts(numDoughnuts):
numDoughnuts= raw_input("How many donuts would you like to order?")
return numDoughnuts
def calculateDoughnutPrice(numDoughnuts, doughnutPrice):
doughnutPrice=DOUGHNUT*float(numDoughnuts)
return doughnutPrice
def calculateSalesTax(doughnutPrice, priceWithTax):
taxAmount= (doughnutPrice*(SALES_TAX))
priceWithTax= taxAmount+doughnutPrice
return priceWithTax
def displayPrice(priceWithTax):
print(priceWithTax)
def main():
getNumDoughnuts(numDougnuts)
calculateDoughnutPrice(numDoughnuts, doughnutPrice)
calculateSalesTax(doughnutPrice, priceWithTax)
displayPrice(priceWithTax)
main()
In main, numDougnuts is indeed not defined when you call getNumDoughnuts. OTOH, the latter function ignores its argument and returns a value, which main in turn ignores. And so forth -- you need to distinguish arguments from return values!
So putting things in proper order your program would become:
DOUGHNUT = 1.75
SALES_TAX = 0.08625
def getNumDoughnuts():
numDoughnuts = raw_input("How many donuts would you like to order?")
return numDoughnuts
def calculateDoughnutPrice(numDoughnuts):
doughnutPrice = DOUGHNUT * float(numDoughnuts)
return doughnutPrice
def calculateSalesTax(doughnutPrice):
taxAmount = doughnutPrice*(SALES_TAX)
priceWithTax = taxAmount + doughnutPrice
return priceWithTax
def displayPrice(priceWithTax):
print(priceWithTax)
def main():
numDoughnuts = getNumDoughnuts()
doughnutPrice = calculateDoughnutPrice(numDoughnuts)
priceWithTax = calculateSalesTax(doughnutPrice)
displayPrice(priceWithTax)
main()
See the difference between arguments and return values? Arguments are what gets into a function (and their values must be defined at the time you call that function). A return value is what gets out of the function -- and usually needs to be bound to a variable, or otherwise used, by the function's caller.
Also, of course, you need to call main, or else nothing happens!-)