I am making a golf scoring program using python 3 which, for each of the 18 holes stores:
the hole number, the par, the difficulty rank, and the target score.
The target score is calculated from the par, difficulty, and handicap (which may be changed by the user).
What would you advise to be the best method for storing this data so that it can be displayed in a table-like fashion, and the target score easily changed if the user edits the value of the handicap?
I don't really know where to start as I have very little experience.
Thanks.
Build a class.
class HoleScore(object):
def __init__(self, hole_number, par, difficulty, handicap=0):
self.hole_number = hole_number
self.par = par
self.difficulty = difficulty
self.handicap = handicap
#property
def target_score(self):
return do_some_calculation_of_attributes(self.par, self.difficulty, self.handicap)
Then you can add a few dunder methods to help things along, or (better) design a function to build a table from a bunch of HoleScore objects. Something like:
# inside class HoleScore
#staticmethod
def make_table(list_of_holes):
"""list_of_holes is a list of HoleScore objects"""
print("Some | headers | here")
for hole in list_of_holes:
fields = [hole.hole_number,
hole.par,
hole.handicap,
hole.target_score]
print("|".join(fields)) # use some string formatting here?
Related
I have a group of objects in python I'd like to sum without losing access to the functionality implemented in the objects.
To illustrate the point, consider this class:
class PlaneTicket:
def __init__(self, origin:str, destination:str):
...
def price(self, pricingDate:date)->float:
'''Returns the best price available on a given date'''
...
In my application I need to be able to sum these objects. You can think of it as having to create a journey that requires two plane tickets.
flight1 = PlaneTicket('london', 'new-york')
flight2 = PlaneTicket('new-york', 'paris')
journey = flight1 + flight2
Now, the interesting thing is, I also want to be able to use the methods in the underlying objects. Eg.
journey.price('2021-06-19')
# Should equal sum(flight.price('2021-06-19') for flight in journey.flights)
So, I could implement a class Journey and make the sum of PlaneTicket objects a Journey object, and also then implement a .price on the Journey class.
However, I may be missing a better solution as I'm sure this is a common problem. Moreover, I'd need different implementations of the Journey class if I'm summing, averaging, or multiplying the PlaneTicket objects.
I suppose the general formulation would be:
I have a collection of objects that implement a method foo()
I want to aggregate these objects (eg. summing them)
I want to be able to call foo on the aggregation and have the return values of the constituent objects aggregated.
You could implement a custom __add__ method like my example below.
class PlaneTicket:
def __init__(self, origin: str, destination: str, price: int):
self.origin = origin
self.destination = destination
self.price = price
def get_price(self):
return self.price
def __add__(self, other):
assert self.destination == other.origin
new_ticket = PlaneTicket(self.origin, other.destination, self.price + other.price)
return new_ticket
flight1 = PlaneTicket("london", "new-york", 1000)
flight2 = PlaneTicket("new-york", "paris", 2000)
journey = flight1 + flight2
print(f"Flying from {journey.origin} to {journey.destination} costs {journey.get_price()}")
Output
Flying from london to paris costs 3000
I am currently working on an assignment where in a particular question I have to take a list of playing cards and, using a class, figure out if it is a Royal Flush.
The lecturer provided a 'skeleton' of code that I have to build the rest around without changing the parts he wrote.
#Lecturer created...
class PokerHand(Hand):
def __init__(self, cards = list()):
Hand.__init__(self, cards)
self.handRank = 0
self.hand = "High Card"
#I have so far added this part...
total_value = 0
val_card_b4 = 0
for card in self.cards:
if Card.getValue(card) > val_card_b4:
total_value += Card.getValue(card)
val_card_b4 = Card.getValue(card)
checkRoyalFlush()
#...to here. However it throws an error that checkRoyalFlush isn't defined.
#The lecturer then had what is below already added.
def checkHand(self):
if self.checkRoyalFlush():
self.handRank = 9
self.hand = "Royal Flush"
print("Test")
I have already created a Card class in an earlier question that allows me to create a card object get the value of the card (A=11, 2-10 equal face value etc.)
My problem is that, once I have checked the cards, I don't know how to 'activate' the if self.checkRoyalFlush(): statement in the checkHand Method.
The code I have to get running is:
h1 = PokerHand([Card('hearts', '10'), Card('clubs', '10'),Card('hearts', '2'),Card('hearts', '3'),Card('spades', 'J')])
h1.show()
print(h1.checkHand())
I would like to understand how to get the if statement working, as I have spent a lond time researching and can't figure it out. I am only a beginner in python and new to the Object Oriented side of it.
Edit: I also don't know how to define 'checkRoyalFlush' without it getting more errors
An if statement such as if self.checkRoyalFlush(): requires a boolean data type as a result, i.e. True or False. Your method needs to return either one of those values:
#Lecturer created...
class PokerHand(Hand):
def __init__(self, cards = list()):
# etc...
def checkHand(self):
# etc...
# add your new method below the methods that already exist
def checkRoyalFlush(self):
# paste your code to check if it is a royal flush here
# if it is a royal flush, then:
return True
# if it is NOT a royal flush, then:
return False
Also you need to refer to your method as self.checkRoyalFlush() as it is a part of the class PokerHand. You aren't doing that in checkHand() method.
It looks like your lecturer want method called checkRoyalFlush() which I'm assuming will return true if your hand is a royal flush or false if it isn't aren't.
Also note that I don't know how you set up your card class, and I don't know what you are calling the suit or value attribute. In the code below, I call .suit for the suit attribute and .value and the value attribute. Change it to whatever you made it as.
Consider code below:
class PokerHand:
def __init__(self, cards = list()):
#your init goes here as above
def checkHand(self):
#checkHand as above
def checkRoyalFlush(self):
check_suit = cards[0].suit #note I don't know what you are calling the suits and values in your hand,
values = ['A','K','Q','J','10'] #values we want to check against
for each_card in cards:
if not (each_card.typing == check_suit and each_card.value in values):
return False
values.remove(each_card.value) #once we found a value we want to remove it from the possible list
return True
The method checkRoyalFlush() will take one card's suit out of the cards list. Since a royal flush must have all the same suit it doesn't matter which card I choose. Here I choose the first card in the list.
Then I iterate through the cards list and check if NOT each of the card's typing is the same, and if each of the values are in the values list
if one card is does not match the requirement, it returns False.
We remove the value we checked so we can make sure it's 1 value and not duplicated values.
If the for loop checking is finished with out returning False, we know that it's a royal flush
Note this is not the most optimal way to do it, it's just one way that shows how it can be done rather clearly.
In part of a program I'm developing I want to perform a linear regression with terms that are some function of a data set X. The exact model used is configurable by the user, particularly which terms (or sets of terms) to use. This involves generating the matrix X' where every row of X' is a function of the corresponding row of X. The columns of X' will be the predictors for my regression.
For example, say my data set is two-dimensional (X has 2 columns). If we denote x and x' as corresponding rows of X and X', then assuming x is two-dimensional x' might be something like
[ 1, x[0], x[1], x[0] * x[1], sqrt(x[0]), sqrt(x[1]), x[0]**2, x[1]**2 ]
You can see these terms come in groups. First is just a 1 (constant), then the untransformed data (linear), then the product of the two data elements (would be all pairwise products if x had more than two dimensions), then square roots and squares of the individual terms.
I need to define all these sets of terms somehow in python, such that each has a user-readable name, function to generate the terms, function to get the number of terms from the dimensions of the input, function to generate labels for the terms based on column labels for the data, etc. Conceptually these all feel like they should be instances of a TermSet class or something similar, but this doesn't quite work because their methods would need to differ. My first thought was to go with something like this:
termsets = {} # Keep track of sets
class SqrtTerms:
display = 'Square Roots' # user-readable name
#staticmethod
def size(d):
"""Number of terms based on input columns"""
return d
#staticmethod
def make(X):
"""Make the terms from the input data"""
return numpy.sqrt(X)
#staticmethod
def labels(columns):
"""List of term labels based off of data column labels"""
return ['sqrt(%s)' % c for c in columns]
termsets['sqrt'] = SqrtTerms # register class in dict
class PairwiseProductTerms:
display = 'Pairwise Products'
#staticmethod
def size(d):
return (d * (d-1)) / 2
#staticmethod
def make(X):
# Some more complicated code that spans multiple lines
...
#staticmethod
def labels(columns):
# Technically a one-liner but also more complicated
return ['(%s) * (%s)' % (columns[c1], columns[c2])
for c1 in range(len(columns)) for c2 in range(len(columns))
if c2 > c1]
termsets['pairprod'] = PairwiseProductTerms
This works: I can retrieve the classes from the dictionary, put the ones I want to use in a list, and call the appropriate methods on each. Still, creating classes with only static attributes and methods seems ugly and unpythonic. Another idea I came up with would be to create a class decorator that could be used like:
# Convert bound methods to static ones, assign "display" static
# attribute and add to dict with key "name"
#regression_terms(name='sqrt', display='Square Roots')
class SqrtTerms:
def size(d):
return d
def make(X):
return numpy.sqrt(X)
def labels(columns):
return ['sqrt(%s)' % c for c in columns]
This gives the same result but is cleaner and much nicer (for myself) to read and write (especially if I need a lot of these). However, the way things actually work under the hood is obscured and anyone else reading this might have a hard idea figuring out what is going on at first. I also thought of creating a metaclass for these but that sounds like overkill. Is there a better pattern I should use here?
Some people will always say that this is an abuse of the language. I say Python was designed to be abusable, and the ability to create DSLs that don't require parsers yet that don't look like lisp is one of its core strengths.
If you really have a lot of these, go with the metaclass. If you do that, in addition to having a term dictionary, you can have attributes that reference the terms, as well. It's really nice, because you can have code like this:
print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)
return results like this:
{'pairprod': <class '__main__.PairwiseProductTerms'>,
'sqrt': <class '__main__.SqrtTerms'>}
<class '__main__.SqrtTerms'>
<class '__main__.PairwiseProductTerms'>
10
The full code that can do that is here:
from types import FunctionType
class MetaTerms(type):
"""
This metaclass will let us create a Terms class.
Every subclass of the terms class will have its
methods auto-wrapped as static methods, and
will be added to the terms directory.
"""
def __new__(cls, name, bases, attr):
# Auto-wrap all methods as static methods
for key, value in attr.items():
if isinstance(value, FunctionType):
attr[key] = staticmethod(value)
# call types.__new__ to finish the job
return super(MetaTerms, cls).__new__(cls, name, bases, attr)
def __init__(cls, name, bases, attr):
# At __init__ time, the class has already been
# built, so any changes to the bases or attr
# will not be reflected in the cls.
# Call types.__init__ to finish the job
super(MetaTerms, cls).__init__(name, bases, attr)
# Add the class into the termsets.
if name != 'Terms':
cls.termsets[cls.shortname] = cls
def __getattr__(cls, name):
return cls.termsets[name]
class Terms(object):
__metaclass__ = MetaTerms
termsets = {} # Keep track of sets
class SqrtTerms(Terms):
display = 'Square Roots' # user-readable name
shortname = 'sqrt' # Used to find in Terms.termsets
def size(d):
"""Number of terms based on input columns"""
return d
def make(X):
"""Make the terms from the input data"""
return numpy.sqrt(X)
def labels(columns):
"""List of term labels based off of data column labels"""
return ['sqrt(%s)' % c for c in columns]
class PairwiseProductTerms(Terms):
display = 'Pairwise Products'
shortname = 'pairprod'
def size(d):
return (d * (d-1)) / 2
def make(X):
pass
def labels(columns):
# Technically a one-liner but also more complicated
return ['(%s) * (%s)' % (columns[c1], columns[c2])
for c1 in range(len(columns)) for c2 in range(len(columns))
if c2 > c1]
print Terms.termsets
print Terms.sqrt
print Terms.pairprod
print Terms.pairprod.size(5)
If you hide away the metaclass and the base Terms class in a separate module, then nobody has to look at it -- just from baseterm import Terms. You could also do some cool auto-discovery / auto-import where dumping modules in the right directory automatically adds them to your DSL.
With the metaclass, the feature set can easily grow organically as you find other things you would like your mini-language to do.
This is a design principle question for classes dealing with mathematical/physical equations where the user is allowed to set any parameter upon which the remaining are being calculated.
In this example I would like to be able to let the frequency be set as well while avoiding circular dependencies.
For example:
from traits.api import HasTraits, Float, Property
from scipy.constants import c, h
class Photon(HasTraits):
wavelength = Float # would like to do Property, but that would be circular?
frequency = Property(depends_on = 'wavelength')
energy = Property(depends_on = ['wavelength, frequency'])
def _get_frequency(self):
return c/self.wavelength
def _get_energy(self):
return h*self.frequency
I'm also aware of an update trigger timing problem here, because I don't know the sequence the updates will be triggered:
Wavelength is being changed
That triggers an updated of both dependent entities: frequency and energy
But energy needs frequency to be updated so that energy has the value fitting to the new wavelength!
(The answer to be accepted should also address this potential timing problem.)
So, what' the best design pattern to get around these inter-dependent problems?
At the end I want the user to be able to update either wavelength or frequency and frequency/wavelength and energy shall be updated accordingly.
This kind of problems of course do arise in basically all classes that try to deal with equations.
Let the competition begin! ;)
Thanks to Adam Hughes and Warren Weckesser from the Enthought mailing list I realized what I was missing in my understanding.
Properties do not really exist as an attribute. I now look at them as something like a 'virtual' attribute that completely depends on what the writer of the class does at the time a _getter or _setter is called.
So when I would like to be able to set wavelength AND frequency by the user, I only need to understand that frequency itself does not exist as an attribute and that instead at _setting time of the frequency I need to update the 'fundamental' attribute wavelength, so that the next time the frequency is required, it is calculated again with the new wavelength!
I also need to thank the user sr2222 who made me think about the missing caching. I realized that the dependencies I set up by using the keyword 'depends_on' are only required when using the 'cached_property' Trait. If the cost of calculation is not that high or it's not executed that often, the _getters and _setters take care of everything that one needs and one does not need to use the 'depends_on' keyword.
Here now the streamlined solution I was looking for, that allows me to set either wavelength or frequency without circular loops:
class Photon(HasTraits):
wavelength = Float
frequency = Property
energy = Property
def _wavelength_default(self):
return 1.0
def _get_frequency(self):
return c/self.wavelength
def _set_frequency(self, freq):
self.wavelength = c/freq
def _get_energy(self):
return h*self.frequency
One would use this class like this:
photon = Photon(wavelength = 1064)
or
photon = Photon(frequency = 300e6)
to set the initial values and to get the energy now, one just uses it directly:
print(photon.energy)
Please note that the _wavelength_default method takes care of the case when the user initializes the Photon instance without providing an initial value. Only for the first access of wavelength this method will be used to determine it. If I would not do this, the first access of frequency would result in a 1/0 calculation.
I would recommend to teach your application what can be derived from what. For example, a typical case is that you have a set of n variables, and any one of them can be derived from the rest. (You can model more complicated cases as well, of course, but I wouldn't do it until you actually run into such cases).
This can be modeled like this:
# variable_derivations is a dictionary: variable_id -> function
# each function produces this variable's value given all the other variables as kwargs
class SimpleDependency:
_registry = {}
def __init__(self, variable_derivations):
unknown_variable_ids = variable_derivations.keys() - self._registry.keys():
raise UnknownVariable(next(iter(unknown_variable_ids)))
self.variable_derivations = variable_derivations
def register_variable(self, variable, variable_id):
if variable_id in self._registry:
raise DuplicateVariable(variable_id)
self._registry[variable_id] = variable
def update(self, updated_variable_id, new_value):
if updated_variable_id not in self.variable_ids:
raise UnknownVariable(updated_variable_id)
self._registry[updated_variable_id].assign(new_value)
other_variable_ids = self.variable_ids.keys() - {updated_variable_id}
for variable_id in other_variable_ids:
function = self.variable_derivations[variable_id]
arguments = {var_id : self._registry[var_id] for var_id in other_variable_ids}
self._registry[variable_id].assign(function(**arguments))
class FloatVariable(numbers.Real):
def __init__(self, variable_id, variable_value = 0):
self.variable_id = variable_id
self.value = variable_value
def assign(self, value):
self.value = value
def __float__(self):
return self.value
This is just a sketch, I didn't test or think through every possible issue.
Being relatively new to Python 2, I'm uncertain how best to organise my class files in the most 'pythonic' way. I wouldn't be asking this but for the fact that Python seems to have quite a few ways of doing things that are very different to what I have come to expect from the languages I am used to.
Initially, I was just treating classes how I'd usually treat them in C# or PHP, which of course made me trip up all over the place when I eventually discovered the mutable values gotcha:
class Pants(object):
pockets = 2
pocketcontents = []
class CargoPants(Pants):
pockets = 200
p1 = Pants()
p1.pocketcontents.append("Magical ten dollar bill")
p2 = CargoPants()
print p2.pocketcontents
Yikes! Didn't expect that!
I've spent a lot of time searching the web and through some source for other projects for hints on how best to arrange my classes, and one of the things I noticed was that people seem to declare a lot of their instance variables - mutable or otherwise - in the constructor, and also pile the default constructor arguments on quite thickly.
After developing like this for a while, I'm still left scratching my head a bit about the unfamiliarity of it. Considering the lengths to which the python language goes to to make things seem more intuitive and obvious, it seems outright odd to me in the few cases where I've got quite a lot of attributes or a lot of default constructor arguments, especially when I'm subclassing:
class ClassWithLotsOfAttributes(object):
def __init__(self, jeebus, coolness='lots', python='isgoodfun',
pythonic='nebulous', duck='goose', pants=None,
magictenbucks=4, datawad=None, dataload=None,
datacatastrophe=None):
if pants is None: pants = []
if datawad is None: datawad = []
if dataload is None: dataload = []
if datacatastrophe is None: datacatastrophe = []
self.coolness = coolness
self.python = python
self.pythonic = pythonic
self.duck = duck
self.pants = pants
self.magictenbucks = magictenbucks
self.datawad = datawad
self.dataload = dataload
self.datacatastrophe = datacatastrophe
self.bigness = None
self.awesomeitude = None
self.genius = None
self.fatness = None
self.topwise = None
self.brillant = False
self.strangenessfactor = 3
self.noisiness = 12
self.whatever = None
self.yougettheidea = True
class Dog(ClassWithLotsOfAttributes):
def __init__(self, coolness='lots', python='isgoodfun', pythonic='nebulous', duck='goose', pants=None, magictenbucks=4, datawad=None, dataload=None, datacatastrophe=None):
super(ClassWithLotsOfAttributes, self).__init__(coolness, python, pythonic, duck, pants, magictenbucks, datawad, dataload, datacatastrophe)
self.noisiness = 1000000
def quack(self):
print "woof"
Mild silliness aside (I can't really help myself when cooking up these artificial example classes), assuming I have a real-world need for a set of classes with this many attributes, I suppose my questions are:
What is the most, uhh, 'pythonic' way of declaring a class with that many attributes? Is it best to put them against the class if the default is immutable, ala Pants.pockets, or is it better to put them in the constructor, ala ClassWithLotsOfAttributes.noisiness?
Is there a way to eliminate the need to redeclare the defaults for all of the subclass constructor arguments, as in Dog.__init__? Should I even be including this many arguments with defaults anyway?
If attributes will vary from instance
to instance make them instance
attribute i.e. create them
inside__init__ using self else if they need to
be shared between class instances
like a constant, put them at class
level.
If your class really need to pass, so
many arguments in __init__, let
derive class use argument list and
keyword arguments e.g.
class Dog(ClassWithLotsOfAttributes):
def __init__(self, *args , **kwargs):
super(ClassWithLotsOfAttributes, self).__init__(*args , **kwargs)
self.coolness = "really cool!!!
No need of passing all variables except few important ones, in
__init__, class can assume some
defaults and user can change them
later on if needed.
Use 4 spaces instead of tab.
if you need to add an extra arg bite, to Dog and keyword arg old too
class CoolDog(ClassWithLotsOfAttributes):
def __init__(self, bite, *args , **kwargs):
self.old = kwargs.pop('old', False) # this way we can access base class args too
super(ClassWithLotsOfAttributes, self).__init__(*args , **kwargs)
self.bite = bite
self.coolness = "really really cool!!!
various ways you useCoolDog
CoolDog(True)
CoolDog(True, old=False)
CoolDog(bite=True, old=True)
CoolDog(old=True, bite=False)