def add_course(gc, course):
global gpacalc
global creditcalc
gpacalc = gpacalc + (gc * course)
creditcalc = (course + creditcalc)
def gpa():
return (gpacalc/creditcalc)
def credit_total():
return(creditcalc)
I am trying to write a file named gpa.py that computes a cumulative GPA using three functions: add_course adds a new course to the running total, and gpa and credit_total gets your cumulative GPA and credit count, respectively. I am attempting to use two global variables to keep track of GPA and credits (both initially 0).
-Invoking gpa.add_course(3.7, 3) should add a 3-credit course with GPA 3.7 to the running GPA and credit count total.
-Invoking gpa.gpa() should retrieve your current total GPA.
-Invoking gpa.credit_total() should retrieve your current total credits earned.
-Invoking gpa.add_course with only one argument (e.g., gpa.add_course(3.7)) should add a 3-credit course.
What am I doing wrong within my code? I am trying to have both the functions nor the file itself containing any print or asking for any input.
Your are throwing a number of things into your code that don't behave the way you expect, because Python is interpreting things differently than you expect. I recommend stepping back and going through a Python tutorial such as learnpython.org, it'll save you a huge amount of time and hassle.
Given the approach you are taking, here is a version that works, with some comments on what I changed.
gpacalc = 0
creditcalc = 0
# If you want the course argument to be optional,
# you need to provide a default value for it.
def add_course(gc, course = 3):
global gpacalc
global creditcalc
# += is the concise way to increment a value:
gpacalc += gc * course
creditcalc += course
def gpa():
# No need to use parenthesis for this return value
# unless you intend the result to be in tuple form.
return gpacalc/creditcalc
def credit_total():
# Same here, no need for parenthesis.
return creditcalc
add_course(3.7, 3)
print(gpa()) # 3.7000000000000006
print(credit_total()) # 3
add_course(3.7)
print(credit_total()) # 6
Related
I'm trying to create a function that is similar to a shopping list where the function asks the users for 2 inputs, the first one being of the item and the second one being the number of said item the user wants, the only caveat being that the total number of items needs to be exactly 10.
def manualInput():
items = []
noitems = []
x = 1
while sum(noitems) != 10 and sum(noitems) < 10:
try:
i = str(input(f'Item {x}: '))
noi = int(input(f'No. of {i}: '))
items.append(i)
noitems.append(noi)
x = x+1
except ValueError:
print('Check inputs and try again')
items.clear()
noitems.clear()
manualInput()
if sum(noitems) > 10:
print('Number of items need to be exactly 10. Try again')
items.clear()
noitems.clear()
manualInput()
return items, noitems
Now this function works perfectly fine if the user does it perfectly the first time around. However if a ValueError is thrown or the sum of the number of items is greater than 10, the lists always return as empty lists despite the function asking the users for their inputs again.
For example if the user wants to type in Oranges and Apples and wants 6 and 4 of each respectively and manages to input all the information correctly, the first time around, the function returns (['Oranges', 'Apples'], [6, 4]) which is what I want.
In the event of an error however, lets say the user accidently inputs Oranges Apples 6 5 , the function does print out Number of items need to be exactly 10. Try again but when the user inputs all the information again, correctly this time, the function does stop but returns ([], []).
I've tried taking out the item.clear() and noitems.clear() commands but this just results in the function returning (['Oranges', 'Apples'], [6, 5])
So to sum it up I don't know why my lists aren't being appended the second time around when I call the function again in the event of an error. It was my understanding that when u call a function within a function it sort of acts like a loop where the function is run again from the top.
It seems you have not understood recursion and the advantage of it.
Your function creates everytime it gets called a new empty items and noitems list. That's why it is impossible to "remember" the last state.
You have to pass them as function arguments - so that the different rounds of calls can share the state of these two lists.
Second, the while loop is an imperative programming construct - recursion replaces the loop - or should replace it. So you have to get rid of it.
Third, naming in programming is one of the most critical and hardest thing.
noitems tells a reader: "there are no items" - but what you mean are 'Number of items" - call it num_items avoid misinterpretable names.
Fourth, programming is communication. Communication requires that you follow conventions of the peer group with/to which you communicate. Writing Python code means you address your code - besides to the machines especially - to the community of people writing Python code (and who have to maintain the machines and your code). - Be it your successor at work, your colleagues, or your instructor in the course. This means: Always follow the Python code conventions and guidelines (style guide https://peps.python.org/pep-0008/ - in other languages - usually the google style guide for that language).
The style guide says: You don't name in python in camelCase, but in snake_case.https://peps.python.org/pep-0008/
So call it manual_input() - not manualInput() (camelCase is JavaScript and Java convention).
def manual_nput(items = [], num_items = []):
if sum(num_items) == 10: # this is the recursion exit condition
return items, num_items # culminating in returning the result
elif sum(num_items) < 10: # these are the different cases
item = str(input(f'Item {len(items)}: '))
num_item = int(input(f'No. of {item}: '))
return manual_input(items + [item], num_items + [num_item])
# they usually end in a recursive call of the function
# with updated arguments
else: # the number of items is > 10
# in this case remove the last item and call the manual_input again
print('Number of items need to be exactly 10. Try again')
return manual_input(items[:-1], num_items[:-1])
# this [:-1] removes the last input and puts the state of
# items and num_items back to the beginning of the previous call
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.
dear expert i am trying to write a simulation and in my code i have a class like this:
... (some def are here)
class multipole:
global xxp,yyp,zzp,x,y,z,xp,yp,zp,t,tm,h
xxp,yyp,zzp,x,y,z,xp,yp,zp =xxpyypzzp() # some initial values calling
#staticmethod
def quad(f1, f2,f3):
global t,h,mass,ksimax
while t < ksimax:
rk4_two(t,h,mass, f1, f2, f3, xxp, yyp, zzp) # rk function for new xxp, yyp and zzp
t = t + h
tm.append(t)
xp.append(xxp[1])
x.append(xxp[0])
yp.append(yyp[1])
y.append(yyp[0])
zp.append(zzp[1])
z.append(zzp[0])
return xp, x, yp,y,zp,z,tm
if __name__ == "__main__":
qp=multipole()
quxp, qux, quyp,quy,quzp,quz,qutm=qp.quad(0.,0.,0.)
hxp, hx, hyp,hy,hzp,hz,htm =qp.quad(0.022,0.,0.)
oxp, ox, oyp,oy,ozp,oz,otm =qp.quad(-0.023,-0.032,0.0 )
my question is this code only calculate (quxp, qux, quyp,quy,quzp,quz,qutm), but not others (others will turn same value of quxp, qux, quyp,quy,quzp,quz,qutm) could you please tell me why? i am new in python any comments will be appreciated.
Ignoring the fact that this code is... somewhat flawed. I think that the problem is that you are using t which is apparently global but you don't reset it anywhere - so this loop:
while t < ksimax:
...
Will only run once, unless you reset t somewhere. Some pseudo code to explain why this happens:
counter = 0
def do_something():
global counter
print "Starting at", counter
while counter <= 10:
print counter
counter += 5
print "Done"
do_something()
# Starting at 0
# 0
# 5
# 10
# Done
do_something() # Called again, the counter is at 10 now:
# Starting at 10
# Done
As others have mentioned, your code could benefit from some heavy refactoring. Some starting points:
Naming! What does xxpyypzzp even mean? Even if it's obvious to you today, it must be hard to read even for you and unless you have Rainman-like memory you will not understand this next week. Try using descriptive names and if you find yourself adding prefixes or suffixes to variables because you run out of names - think about encapsulating some of this complexity in a class. It seems like the suffixes xp, x, yp, y, zp, z and tm are used a lot. At least create a named tuple to hold these values.
Global variables is generally considered harmful. They make it hard to reason about code - which is why you got this bug in the first place. If you are sprinkling global statements over your code there is time to redesign it. Think about which part of your code should "own" which parts of the state.
Python has a coding standard, called PEP8 - read it and try to follow it.
Question: write a program which first defines functions minFromList(list) and maxFromList(list). Program should initialize an empty list and then prompt user for an integer and keep prompting for integers, adding each integer to the list, until the user enters a single period character. Program should than call minFromList and maxFromList with the list of integers as an argument and print the results returned by the function calls.
I can't figure out how to get the min and max returned from each function separately. And now I've added extra code so I'm totally lost. Anything helps! Thanks!
What I have so far:
def minFromList(list)
texts = []
while (text != -1):
texts.append(text)
high = max(texts)
return texts
def maxFromList(list)
texts []
while (text != -1):
texts.append(text)
low = min(texts)
return texts
text = raw_input("Enter an integer (period to end): ")
list = []
while text != '.':
textInt = int(text)
list.append(textInt)
text = raw_input("Enter an integer (period to end): ")
print "The lowest number entered was: " , minFromList(list)
print "The highest number entered was: " , maxFromList(list)
I think the part of the assignment that might have confused you was about initializing an empty list and where to do it. Your main body that collects data is good and does what it should. But you ended up doing too much with your max and min functions. Again a misleading part was that assignment is that it suggested you write a custom routine for these functions even though max() and min() exist in python and return exactly what you need.
Its another story if you are required to write your own max and min, and are not permitted to use the built in functions. At that point you would need to loop over each value in the list and track the biggest or smallest. Then return the final value.
Without directly giving you too much of the specific answer, here are some individual examples of the parts you may need...
# looping over the items in a list
value = 1
for item in aList:
if item == value:
print "value is 1!"
# basic function with arguments and a return value
def aFunc(start):
end = start + 1
return end
print aFunc(1)
# result: 2
# some useful comparison operators
print 1 > 2 # False
print 2 > 1 # True
That should hopefully be enough general information for you to piece together your custom min and max functions. While there are some more advanced and efficient ways to do min and max, I think to start out, a simple for loop over the list would be easiest.