It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I am having trouble with an hw problem in my CS class. The problem has to do with creating a class in python. Heres the prompt
Your class should be named Student, and you should define the following methods:
__init__: This method initializes a Student object.
Parameters: a name, a GPA, and a number of units taken
• Should initialize instance variables for name, GPA, and units based on
the information that was passed in. If the GPA or number of units is negative, sets it to 0. (Donʼt worry about non-numeric values in this method.)
update: This method updates the instance variables of the Student object if the Student takes a new class.
• Parameters: units for the new class, grade points earned (as a number) in the new class.
• Should modify the instance variable for units to add the units for the new class
• Should modify the GPA to incorporate the grade earned in the new class. (Note that this will be a weighted average using both the unit counts and both sets of GPAs.)
get_gpa: This method should return the studentʼs GPA.
get_name: This method should return the studentʼs name.
Heres what i have
class Student:
def__init__(self,name,GPA,units):
if units <0:
units=0
if GPA<0:
GPA=0
self.name=name
self.GPA=GPA
self.units=units
def update(newunits,GPE):
thats all i can come up with
Let’s go through some points which will hopefully help you:
Constructor (__init__)
If the GPA or number of units is negative, sets it to 0.
So you probably want to check each separately:
if units < 0:
units = 0
if GPA < 0:
GPA = 0
Update method
Methods in general take a reference to the current object as the first argument, named self per convention (just as in __init__). So your update method declaration should look like this:
def update(self, newunits, GPE):
...
Should modify the instance variable for units to add the units for the new class
Just as you did in the constructor, you can access instance variables using self.varname. So you probably want to do something like this:
self.units += newunits
Should modify the GPA to incorporate the grade earned in the new class. (Note that this will be a weighted average using both the unit counts and both sets of GPAs.)
Just as you update self.units you have to update self.GPA here. Unfortunately, I have no idea what a GPA is and how it is calculated, so I can only guess:
self.GPA = ((self.GPA * oldunits) + (GPE * newunits)) / self.units
Note that I introduced a new local variable oldunits here that simply stores the units temporarily from before it was updated (so oldunits = self.units - newunits after updating).
get_gpa and get_name
These are simple getters that just return a value from the object. Here you have an example for the units, i.e. you should figure it out for the actual wanted values yourself:
def get_units (self):
return self.units
Note that it’s rather unpythonic to have getters (get_x methods), as you would just expect people to access the properties directly (while handling them with care).
I'll help you to complete the question, but let me point out a little mistake first:
if units <0 and GPA <0:
units=0
GPA=0
This will set units and GPA to zero only if they are both negative. You'll want to set each to zero if it's negative, even if the other is not. Change it to:
if units < 0: units = 0
if GPA < 0: GPA = 0
Concerning your update method, the correct signature would be:
def update(self, newunits, GPE):
Python object methods should always start with self.
Now, I'm not sure about how to calculate the GPA (we use a different system were I live), but according to some quite google queries, your update method should be something like:
def update(self, newunits, GPE):
GPE_earned_before = self.GPA * self.units
total_GPE = GPE_earned_before + GPE
self.GPA = total_GPE / (self.units + newunits)
self.units += newunits
I used a lot of variables here, to make things clear, but this can be shortened to:
def update(self, newunits, GPE):
self.GPA = (self.GPA * self.units + GPE) / (self.units + newunits)
self.units += newunits
Related
I am trying to create a Python Class to calculate the Kelly Criterion formula in order to determine the precise bet size for an individual sport's investment. I am not very good with using the Class function or init function and could use some help.
The Class I am trying to create uses three functions:
Function 1 asks the user to input the estimated win percentage of the bet (saved to variable 'winP').
Function 2 asks the user to input the American odds for this particular bet. I then convert the American odds to Decimal odds to use with the Kelly Criterion formula (saved to variable 'odds').
Function 3 takes 'winP' and 'odds' and implements this data into the Kelly Criterion formula.
The Kelly Criterion formula that I am using is:
Kelly Criterion (kCrit) = ((odds - 1) * (1 - winP)) / (odds - 1)
'odds' is the Decimal form of the American odds after conversion. 'winP' in the expected winning probability of this particular bet.
I was able to get the 1st and 2nd function to work perfectly (win_percentage, convert_to_decimal), however I was unable to get the 3rd function to work (implement_kc)
Here is my code below:
class KellyCriterion:
def win_percentage(percent):
winP = int(input('What is your win percentage?: '))
return winP
def convert_to_decimal(odds):
odds = int(input('What are the American odds?: '))
if odds > 0:
odds = (odds/100) + 1
return odds
elif odds < 0:
odds = -(100/odds) + 1
return odds
def implement_kc(winP, odds):
kCrit = ((odds - 1) * (1-winP)) / (odds-1)
return kCrit
winPercent = KellyCriterion()
winPercent.win_percentage()
betSize = KellyCriterion()
betSize.convert_to_decimals()
I was not sure how to call on the 3rd function properly:
kelly = KellyCriterion()
kelly.implement_kc()
I received an error: NameError: name 'winP' is not defined.
I am a beginner with using Class functions and could use some help. I also tried using an init(self) function but not exactly sure how those work.
Any suggestions would be greatly appreciated. Thanks in advance for any help that you may offer.
Just to clarify the 1st function (win_percentage) and 2nd function (convert_to_decimal) work just fine. I am having issues with the 3rd function (implement_kc).
I would like to find a way to call on the KellyCriterion Class to: 1) ask the user what is their win percentage; 2) ask the user what are the American odds; 3) implement both of their responses into the Kelly Criterion formula to find out the appropriate bet size.
Thanks again!
If you want to write a class, you need to pass self to the functions. Moreover, the way you have winPercent = KellyCriterion() and betSize = KellyCriterion() means you have two separate instances of the KellyCriterion class, which don't communicate with one another. What you want, is a single instance so you can assign both winP and odds to that instance, otherwise any call to the implement_kc() method is going to be missing values and return an error.
As an aside, here's a post that shows a class-based implementation of the Kelly Criterion and some more background on how it's done. Could be helpful for reference.
Anyway, here's some code that will work, at least if I understand what you're trying to accomplish:
class KellyCriterion:
def win_percentage(self):
winP = int(input('What is your win percentage?: '))
self.winP = winP / 100
def convert_to_decimal(self):
odds = int(input('What are the American odds?: '))
if odds > 0:
self.odds = (odds/100) + 1
elif odds < 0:
self.odds = -(100/odds) + 1
def implement_kc(self):
kCrit = ((self.odds - 1) * (1-self.winP)) / (self.odds-1)
return kCrit
If we run it:
KC = KellyCriterion()
KC.win_percentage()
KC.convert_to_decimal()
print(f"Wager: {KC.implement_kc():.2f}%")
If we enter, say 51 and -110 when prompted for input, then we get:
Wager: 0.49%
Now each of the input functions you defined assign an attribute to the class (e.g. self.winP and self.odds) that the implement_kc() method will use later when you call it.
class Athlete:
def __init__(self, name, points):
self.name = name
self.points = points
def calculateRacePoints(name):
for i in range(eventTotalVar):
racePoints = checkOverallPlacement(placementVar, eventType=eventVar) + checkPercentagePlacement(placementVar, totalVar, eventType=eventVar) + checkImprovement(seedTime, prelimTime, finalTime) # uses created 2 functions and finds the total
racePoints = racePoints + racePoints
return float(racePoints / eventTotalVar)
This is basically creating an athlete with inputted specifications. It will return the average points attained in the race (total points divided by number of events).
Do classes qualify as an algorithm? If so, do my two functions within it also qualify as an algorithm? What specifically makes an algorithm, well, an algorithm?
Oxford Dictionary defines an Algorithm as:
"A process or set of rules to be followed in calculations or other
problem-solving operations, especially by a computer".
By that definition something as simple as print("Hello World") would technically be considered an algorithm.
looking at your code:
class Athlete:
def __init__(self, name, points):
self.name = name
self.points = points
def calculateRacePoints(name):
for i in range(eventTotalVar):
racePoints = checkOverallPlacement(placementVar, eventType=eventVar) + checkPercentagePlacement(placementVar, totalVar, eventType=eventVar) + checkImprovement(seedTime, prelimTime, finalTime) # uses created 2 functions and finds the total
racePoints = racePoints + racePoints
return float(racePoints / eventTotalVar)
You have multiple algorithms at work.
class Athlete
Contains two or more algorithms
Contains logical and mathematical concepts
def __init__(self, name, points)
Solves the problem of describing who or what the athlete is
It allows you to create an athlete and give that athlete a name and score/points
def calculateRacePoints(name)
Solves the problem of interacting with the athlete
It allows you to get information about this athlete's score/points
Both of your class methods are algorithms that work together to help the program create new athletes and interact with them.
I would imagine you need to provide more detail to complete the assignment, but I hope this gets you started.
I'm working on a school project which has to store the names of people and their respective score on a test in a list so that I can manipulate it to find averages as well as printing out each persons score with their name. Relatively new to Python so any help is appreciated :)
I would recommend using a dictionary. This pairs keys (the name of students) to values (the score on a test). Here is an example below that gets you the output that you would want.
import math
student_scores = {}
student_scores['Rick'] = 89
student_scores['Pat'] = 79
student_scores['Larry'] = 82
score_list = []
for name, score in student_scores.items():
score_list.append(score)
print(name.title() + "'s score was: " + str(score) + '%')
sum_scores = sum(score_list)
division_scores = len(score_list)
average_score = sum_scores / division_scores
print('The average score was {0:.2f}%'.format(average_score))
I created an empty dictionary that you will use to add student names and scores to a list. So in the dictionary (student_scores) The student name 'Rick' will be a key, and the score 89 will the value. I do this for 2 additional students, pairing their name up with the score that they received.
I create an empty list called score_list. You'll use this list later to add he sum of all scores, and divide by the number of total scores to get an average score for your test.
We start a for loop that iterates over each key and value in your dictionary. For each score, we append it to the empty score list. For each name and score, we print a message showing what the student got on the test.
Now that we have appended the scores to the dictionary we can use the sum method to get the sum of all scores in your score list. We put it in a variable called sum_scores. We also get the number of scores in your list by finding the length of the list (which will be 3 in this case since I put 3 scores in it). We will store that in a variable called division_scores (since I am dividing the sum of all scores by the number of scores recorded). We create a variable called average_score which is the result of the sum of scores divided by the total number of observations.
We then print what the average score was using the .format() method. We just format the average score so that you get it to extend two decimal places {0:.2f}%.
Your output is as follows:
Rick's score was: 89%
Pat's score was: 79%
Larry's score was: 82%
The average score was 83.33%
The above answer is a great data structure for pairing strings. It'll set you on the right track for enumerating scores, averages, etc in simple cases.
Another way to store relationships is with classes (or tuples, at the bottom!) There's a rough sketch of an OOP approach below.
The most important parts are
The properties of the ExamAttempt class store the information (names, scores)
In the Exam.record_attempt method, a new ExamAttempt object is created from the ExamAttempt class and added to the list of attempts on the Exam object.
From here, you could easily add other features. You'd probably want to model a Question and Answer, and maybe a Student object too, if you're going all out. If you store questions and answers, as well as which answer each student selected, you can start doing things like throwing out questions, grading on a curve, discovering questions to throw out, etc. The OOP approach makes it easier to extend functionality like plotting all kinds of fancy graphs, export to CSV or Excel, and so on.
Not all of the code below is necessary.. it can definitely be simplified a little, or reimagined entirely, but hopefully this should give you enough to start looking down that path. Even if it seems complicated now, it's not that bad, and it's what you'll want to be doing eventually (with Python, anyway!)
class ExamAttempt:
def __init__(self, id, name, correct, total):
self.id = id
self.name = name
self.correct = correct
self.total = total
self.score = (self.correct / float(self.total))
def __repr__(self):
return "<ExamAttempt: Id={}, Student={}, Score={}>".format(self.id, self.name, self.score)
class Exam:
def __init__(self, name, questions):
self.name = name
self.attempts = []
self.questions = questions
self.num_questions = len(questions)
def __str__(self):
return "<Exam ({})>".format(self.name)
def load(self, filename):
pass
def saveAttemptsToFile(self, filename):
pass
def record_attempt(self, student_name, num_correct):
id = len(self.attempts) + 1
self.attempts.append(
ExamAttempt(id, student_name, num_correct, self.num_questions))
def get_student_attempt(self, student_name):
for att in self.attempts:
if student_name == att.name:
return att
def get_average_score(self):
return "homework"
def get_results_by_score(self):
return sorted(self.attempts, key=lambda x: x.score, reverse=True)
def get_attempts_by_name(self):
return sorted(self.attempts, key=lambda x: x.name)
if __name__ == '__main__':
questions = ['Question?' for i in range(100)] # Generate 100 "questions" = 100%
exam = Exam('Programming 101', questions)
data = [('Rick', 89), ('Pat', 79), ('Larry', 82)]
for name, correct in data:
exam.record_attempt(name, correct)
for attempt in exam.get_results_by_score():
print("{} scored {}".format(attempt.name, attempt.score))
I'm making a simple text-based game.
My full code is 150 lines, so I'll include what I think is relevant. Let me know if you need more.
The problem is that this line:
print("You deal " + str(hero.damage) + " damage to the monster")
returns only 5 instead of 5 + level as wanted.
class Hero:
def __init__(self):
self.level = 0
self.damage = 5 + self.level #This is the problem line. Self.level seems to be treated as equal to 0 even when it is higher than 0.
self.experience = 0
def level_up(self): #triggered on monster death
xp_required = 15
if self.experience >= xp_required:
self.level += 1
hero = Hero()
I know hero.level_up() is successful because:
print(hero.level)
returns a level that gets correctly updated as appropriate.
I'm guessing either:
self.damage only gets calculated once, then stores that value even after components of it have changed.
or:
There is some kind of issue with calling __init__ values within __init__.
or:
The calculation is done on the class Hero, not the object Hero()
You are right, self.damage is only written to once: In the __init__ constructor which is itself only called once (when the object is created). And at that time, self.level is zero, so self.damage will be always 5.
You have two options:
Either you change your code to always update the damage as well whenever you change the level. In order to avoid spreading the damage calculation logic into multiple places, you would create a helper method to update the damage value:
def update_damage(self):
self.damage = 5 + self.level
def level_up(self):
if self.experience <= 15:
self.level += 1
self.update_damage()
If the damage value is only ever dependent on the level, you could also make it a update_level(new_level) method; but I opted out of that solution here since it’s not uncommon to have some other things affect damage later on as well (e.g. damage potions or whatever).
Or you change damage into a calculated property, so the damage value is calculated whenever you access it. That has the overhead that it needs to be calculated every time instead of the value being stored somewhere, but on the other hand, you have the ultimate truth about the damage value and you do not need to remember to update it elsewhere:
def __init__(self):
self.level = 0
self.experience = 0
#property
def damage(self):
return 5 + self.level
Your guess about self.damage being calculated once is correct. As #Willem Van Onsem mentions, self.damage= 5+self.level is an assignment and not an equation. You will need to manually update it each time you change self.level.
The most suitable approach to me seems to be wrap it into a property such as:
#property
def damage(self):
return 5 + self.level
The way that you are treating equality is more closely related to reactive programming which is often emulated with properties in python.
I'm making a game and one of the methods calculates a character's base hit numbers based on skill values. The method currently calculates each value individually, since each skill can be used at short, medium, and long range.
I originally thought I could combine the skills into a tuple and iterate over it, dynamically creating each hit number. But I don't know if it's actually possible, since I currently have each hit number assigned to it's own variable.
I also thought about creating a method for each range, and passing the tuple as an argument. I could create a new tuple or list with the resulting values and then assign them to the individual variables, but I don't see how it would be any better than do it this way, except that it won't look so copy & pasted.
Here's what I currently have:
def calcBaseHitNumbers(self, dict):
"""Calculate character's base hit numbers depending on skill level."""
self.skill_dict = dict
self.rifle = self.skill_dict.get('CRM', 0)
self.pistol = self.skill_dict.get('PST', 0)
self.big_gun = self.skill_dict.get('LCG', 0)
self.heavy_weapon = self.skill_dict.get('HW', 0)
self.bow = self.skill_dict.get('LB', 0)
#self.skill_tuple = (self.rifle, self.pistol, self.big_gun, self.heavy_weapon,
# self.bow)
#---Short range
## for skill in self.skill_tuple:
## self.base_hit_short = skill * 0.6
self.charAttribs.bhCRM_short = self.rifle * 0.6
self.charAttribs.bhPST_short = self.pistol * 0.6
self.charAttribs.bhHW_short = self.heavy_weapon * 0.6
self.charAttribs.bhLCG_short = self.big_gun * 0.6
self.charAttribs.bhLB_short = self.bow * 0.6
#---Med range
self.charAttribs.bhCRM_med = self.rifle * 0.3
self.charAttribs.bhPST_med = self.pistol * 0.3
self.charAttribs.bhHW_med = self.heavy_weapon * 0.3
self.charAttribs.bhLCG_med = self.big_gun * 0.3
self.charAttribs.bhLB_med = self.bow * 0.3
#---Long range
self.charAttribs.bhCRM_long = self.rifle * 0.1
self.charAttribs.bhPST_long = self.pistol * 0.1
self.charAttribs.bhHW_long = self.heavy_weapon * 0.1
self.charAttribs.bhLCG_long = self.big_gun * 0.1
self.charAttribs.bhLB_long = self.bow * 0.1
How would you refactor this so it's more dynamic?
Edit: I guess what I want to do is something like this:
Have a tuple (like the one I commented out) and iterate over it 3 times, each time making a new value (for each skill) based on the modifier for each particular range. The resulting value is then automatically assigned to it's respective variable.
In my head, it makes sense. But when I actually try to code it, I get lost. The problem, I think, is that this is the first "real" program I've written; all I've done before are small scripts.
This is only the 0.1 version of my program, so it's not critical to refactor it now. However, it seems very un-Pythonic to do this manually and I also want to "future-proof" this in case things change down the road.
It feels like what you really want is a class representing the weapon, with attributes to handle the base values and calculate hit values with various modifiers. Here's a simple example:
SHORT_RANGE = 'S'
MEDIUM_RANGE = 'M'
LONG_RANGE = 'L'
SHORT_RANGE_MODIFIER = 0.6
MEDIUM_RANGE_MODIFIER = 0.3
LONG_RANGE_MODIFIER = 0.1
class Weapon(object):
def __init__(self, code_name, full_name, base_hit_value,
short_range_modifier=None, medium_range_modifier=None,
long_range_modifier=None):
self.code_name, self.full_name = code_name, full_name
self.base_hit_value = base_hit_value
self.range_modifiers = {
SHORT_RANGE: short_range_modifier or SHORT_RANGE_MODIFIER,
MEDIUM_RANGE: medium_range_modifier or MEDIUM_RANGE_MODIFIER,
LONG_RANGE: long_range_modifier or LONG_RANGE_MODIFIER,
}
def hit_value(self, range, modifier=1):
return self.base_hit_value * self.range_modifiers[range] * modifier
From there, you might create instances of Weapon inside your Character object like so:
self.rifle = Weapon('CRM', 'rifle', 5)
self.pistol = Weapon('PST', 'pistol', 10)
And then if, say, the character fires the pistol at short range:
hit_value = self.pistol.hit_value(SHORT_RANGE)
The extra argument to the hit_value() method can be used to pass in character- or situation-specific modifications.
Of course, the next step beyond this would be to directly model the weapons as subclasses of Weapon (perhaps breaking down into specific types of weapons, like guns, bows, grenades, etc., each with their own base values) and add an Inventory class to represent the weapons a character is carrying.
All of this is pretty standard, boring object-oriented design procedure, but for plenty of situations this type of thinking will get you off the ground quickly and provide at least a little bit of basic flexibility.
Lets see if I understand you scenario: each weapon has its own distinct hit point so a rifle may have 1, a heavy weapon may have 2 etc. Then each character has a short, medium and long value to be multiplied by the hit point of the weapon.
You should consider using a Strategy design. That is create a weapon superclass with a hit point property. Create sub class weapons for rifle, pistol, bow etc. I am sure that the differences between the weapons are more than just the hit points.
Then the Character has one or more weapons depending on your gameplay. To calculate the hit point for a particular weapon is as simple as
current_weapon * self.medium
If you decide to add more weapons later on then you do not have to edit your Character code because your character can handle any weapon.
In Pseudo Python
class Weapon
hit = 1
#other properties of weapon
class Rifle(Weapon)
#other properties of Rifle
class Pistol(Weapon)
#other properties of Pistol
class Character
weapon = Rifle()
long=0.6
def calcHit()
return self.long*weapon.hit
john = Character()
john.weapon= Rifle()
john.calcHit
#Vinko: perhaps make calcBaseHitNumbers, do the "if not self.calculatedBase:" check internally, and just no-op if it's been done before. That said, I can't see the pressing need for precalculating this information. But I'm no Python performance expert.
What sense of dynamic do you mean? What is likely to vary - the number of skills, or the weighting factors, the number of ranges (short, med, long) or all of these?
What happens to the (e.g.) bhPST_* values afterwards - do they get combined into one number?
One thing that leaps out is that the list of skills is hardwired in the code - I would be inclined to replace the bh variables with a method
So (please take into account I don't know the first thing about Python :) )
def bh_short(self, key)
skill = self.skill_dict.get(key, 0)
return skill * 0.6
Now you can keep a list of skills that contribute to hit points and iterate over that calling bh_short etc.
Possibly also pass the range (long med short) unto the function, or return all three values - this all depends on what you're going to do next with the calculated hitpoints.
Basically, we need more information about the context this is to be used in
I would have a class for the character's attributes (so you don't have heaps of things in the character class) and a class for a weapon's attributes:
class WeaponAttribute(object):
short_mod = 0.6
med_mod = 0.3
long_mod = 0.1
def __init__(self, base):
self.base = base
#property
def short(self):
return self.base * self.short_mod
#property
def med(self):
return self.base * self.med_mod
#property
def long(self):
return self.base * self.long_mod
class CharacterAttributes(object):
def __init__(self, attributes):
for weapon, base in attributes.items():
setattr(self, weapon, WeaponAttribute(base))
Have a CharacterAttributes object in the character class and use it like this:
# Initialise
self.charAttribs = CharacterAttributes(self.skill_dict)
# Get some values
print self.charAttribs.CRM.short
print self.charAttribs.PST.med
print self.charAttribs.LCG.long