I'm trying to get a class to spit out a number with units. The purpose of it having units would be to be able to work with the number later, but without the units getting in the way as a string. Though I have no idea how to do this. I'm quite new with (actually understanding) classes, I'm not even sure if what I ask is possible or not.
My goal is to make a class for making atoms, based on their protons, electrons and neutons. The thing I wanna try is to be able to see the units of the mass (in kgs for my purpose) when I try printing it. Here's what I have:
class Atom:
def __init__(self, protons, electrons, neutrons):
ElemCharge = 1.6021765*(10**-19)
UMAS = 1.66054*(10**-27)
self.protons = protons
self.electrons = electrons
self.neutrons = neutrons
self.charge = ElemCharge*(self.protons - self.electrons)
self.mass = (self.protons + self.neutrons)*UMAS
def main():
Hydrogen = Atom(1,1,0)
print (Hydrogen.mass)
Argon = Atom(18,18,22)
print (Argon.mass)
if __name__ == "__main__":
main()
This code works completely fine, so no worries about that :p
Is there a way to even do this? If so, how can it be done? Thanks!
I'm not sure if this is exactly what you're looking for, but you could have a method inside the Atom class that prints the mass of the atom plus a unit string.
class Atom:
def __init__(self, protons, electrons, neutrons):
ElemCharge = 1.6021765*(10**-19)
UMAS = 1.66054*(10**-27)
self.protons = protons
self.electrons = electrons
self.neutrons = neutrons
self.charge = ElemCharge*(self.protons - self.electrons)
self.mass = (self.protons + self.neutrons)*UMAS
def print_mass_str(self):
print('{} {}'.format(self.mass, 'kg'))
Then this:
Argon = Atom(18,18,22)
print(Argon.mass)
Argon.print_mass_str()
would print:
6.64216e-26
6.64216e-26 kg
There are ways of doing it, but firstly you should ask yourself whether you want this. Having different units can get confusing. You can put conversions at the appropriate places (e.g. after reading the input from user) and have your system work solely on a given unit (that's why we have SI units, after all). Being able to support multiple units internally not only complicates the code, but introduces another source of possible confusion.
There are packages which do this for you, such as units, numericalunits or pint.
An example taken from units documentation is:
>>> from units import unit
>>> metre = unit('m')
>>> second = unit('s')
>>> print(metre(10) / second(2))
5.00 m / s
>>> print(metre(10) ** 3)
1000.00 m * m * m
See how metre creates a meter value, and it keeps track of its usage. It has also support for defining custom units.
Therefore, you could simply store the values in your class as values from units or other package, and you're all set. I looked a bit into the code of units and is quite short and I think it's a good source of learning how to handle stuff like this in your own code.
I have to cite the failure of Nasa Mars Climate Orbiter, which was due to a unit discrepancy.
To override the string representation of the number, make a wrapper class:
class FloatWrapper:
def __init__(self, float, unit):
self.float = float
self.unit = unit
def __getattr__(self, key):
try:
return object.__getattr__(self, key)
except AttributeError:
return getattr(self.float, key)
def __str__(self):
return str(self.float) + self.unit
Now in your __init__, after defining self.mass, add:
self.mass = FloatWrapper(self.mass, 'kg')
This works?
Basically I have added another property to the Atom class so that all objects of type Atom can use it. Another way of doing it would be to pass it as you are doing with the neutrons/protons/electrons. That way it you can perform your own calculations (if there was a requirement to do so) given a unit (say you wanted to show weight in grams for Hydrogen , while in KGs for Argon)
class Atom:
def __init__(self, protons, electrons, neutrons):
ElemCharge = 1.6021765*(10**-19)
UMAS = 1.66054*(10**-27)
self.protons = protons
self.electrons = electrons
self.neutrons = neutrons
self.charge = ElemCharge*(self.protons - self.electrons)
self.mass = (self.protons + self.neutrons)*UMAS
self.massUnit = "kgs"
def main():
Hydrogen = Atom(1,1,0)
print ("{0} {1}".format(Hydrogen.mass,Hydrogen.massUnit))
Argon = Atom(18,18,22)
print ("{0} {1}".format(Argon.mass,Argon.massUnit))
if __name__ == "__main__":
main()
Output
1.66054e-27 kgs
6.64216e-26 kgs
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 am new to python, about 3 days, and I am not sure if I have worded the question properly.
I have a class:
class blue_slime:
nom = "BLUE SLIME"
img = " /\ \n( o o)"
str = 10
int = 5
dex = 5
con = 10
spd = 10
hp = ((con + str) / 2)
mp_bonus = 1
and I want to use the variables from this class in another function.
def encounter(nom, hp, img):
print(char_name + " encountered a " + nom + "!!!")
wait()
while hp > 0:
battle(hp, img)
else:
stats()
now I know that I could call this by using
encounter(blue_slime.nom, blue_slime.hp, blue_slime.img)
but I would much rather (and think it may be necessary for my program down the line) be able to just use the class name as the function argument and then in the function I can just utilize all variables without having to write them in each time. While this may sound like laziness, I am thinking about making the encounter be random, so 10% chance to encounter(blue_slime) 10% chance to encounter(green_slime).
I feel the easiest way to implement this would be to somehow condense all the variables in "class blue_slime" into one name.
please let me know if there is a way to do this, perhaps I have just not learned it yet.
You can just pass the class into the function is that's what you wanna do. That will solve your problem:
def encounter(monster):
monster.hp
monster.img
# etc.
Here's some tips:
As was already mentioned in the comments on your question, you probably want to be using instances of those classes instead of the actual classes. I'll give a sample class with a few pointers:
class BlueSlime: # Using CapCase like this is normal for class names
# You can use this space to make class variables.
# These will be the same across all the classes.
# Probably use this for initializing your instances
base_hp = 5
base_int = 10
base_dmg = 3
def __init__(self): # The "Constructor" of your instances
self.current_hp = self.base_hp # self refers to the instances
self.int = self.base_int
self.dmg = self.base_dmg
The instance thing is nice because if some of your slimes take dmg, you don't necessarily want them all to take dmg.
bs1 = BlueSlime() # Init the instance
bs2 = BlueSlime()
# bs1 takes 1 dmg (May want a method to do this)
bs1.hp -= 1
bs1.hp
# Now 4
bs2.hp
# Still 5
Getting back to your question, at this point, you can pass these instances into your encounter function.
def encounter(monster):
# Something happens here to reduce the hp, it will reduce the instance's hp
# Something happens here to deal dmg, you can look it up on the instance
player.hp -= monster.dmg # Something like this....
# etc
I'm working on building a simple python program for a class which will run on a Raspberry Pi and an Arduino to direct a telescope. I had started to learn python some time ago, and I'm having trouble getting my functions to work properly. Right now, I have this:
import ephem
def const(p, d): # find the constellation #
def loc():
sbend = ephem.Observer()
sbend.lat = '41.67'
sbend.lon = '86.26'
p = getattr(ephem, p)
p.compute(sbend)
print p.alt, p.az
o = getattr(ephem, p)
print ephem.constellation(o(d))
return loc()
const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
From what I remember, a function inside another can call a variable from the parent. Can it also work the other way round like I have at the end? I'd like to be able to print the constellation (which is working) as well as the alt and az of the planet based on the hardcoded location. For some reason, it isn't calculating the altitude and azimuth though. Thoughts?
EDIT
I added return loc() on line 14.
I was doing more reading and some other threads said that to get to an inner function, it needs to be returned at the end of the parent. But, it's still not working for me.
I am not clear on why you have one function inside of another, so I might be missing part of the problem that you are trying to solve; but if I wanted to determine in what constellation a planet lies, where the planet's name and the date are provided as inputs, then I would simply perform those steps all in a row, without any complicated functions-inside-of-functions:
import ephem
def const(planet_name, date_string):
planet_class = getattr(ephem, planet_name)
planet = planet_class()
south_bend = ephem.Observer()
south_bend.lat = '41.67'
south_bend.lon = '-86.26' # west is negative
south_bend.date = date_string
planet.compute(south_bend)
return ephem.constellation((planet.ra, planet.dec))
print const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
Taking #Brandon's example, here is my final code:
import ephem
def const(planet_name, date_string):
planet_class = getattr(ephem, planet_name)
planet = planet_class()
south_bend = ephem.Observer()
south_bend.lat = '41.67'
south_bend.lon = '-86.26'
south_bend.date = date_string
planet.compute(south_bend)
print ephem.constellation((planet.ra, planet.dec))
return planet.alt, planet.az
print const(raw_input('Planet: '), raw_input('yyyy/mm/dd: '))
I realized after looking at it that he was using planet.ra and planet.dec to locate the background constellation, not to print it's coordinates in the sky. All I did was add the return call at the end to print the altitude and azimuth data.
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