So I am a complete newbie to coding and need some help. I am trying to create a code for a tip calculator but am not quite sure where I am going with it. I was never in class to be taught by my teacher so I am going out on a whim with this. There is a requirement to have a class but I know I am going about it the wrong way. Any help is appreciated. This is what I have so far:
import decimal
class Tip:
def __init__(self):
self.tip=0
def __str__(self):
return 'Tip['+str(self.sub_total)+' * '+str(self.percentage)+']'
def sub_total():
self.sub_total = input()
def percentage():
self.percentage = input()
def get_tip(percentage, sub_total):
self.percentage = decimal.Decimal(percentage)
self.sub_total = decimal.Decimal(sub_total)
self.tip = ((sub_total * percentage) / 100)
self.total = (sub_total + tip)
return self.__str__()
t = Tip()
print ("How much is the bill?")
t.sub_total()
print ("What percentage should the tip be?")
t.percentage()
print (t.get_tip())
Everytime I run it I get this:
get_tip() takes exactly 2 arguments (1 given)
Like I said, I am kindof making it up as I go and any help is appreciated.
Hoo boy, there's a lot of things to cover. I'll try to get it all, but will start with working code.
class Bill(object): # note: not Tip!
def __init__(self, sub_total):
self.sub_total = sub_total
def calculate_tip(self, tip_pct):
return self.sub_total * tip_pct
def calculate_total(self, tip_pct):
return self.sub_total * (1 + tip_pct)
This defines a Bill
object. If we want to use it, we could do:
subtotal = float(raw_input("Bill subtotal: "))
b = Bill(subtotal)
Then to get the tip we could do
tip_percentage = float(raw_input("Tip Percent (15% --> 0.15): "))
tip_amt = b.calculate_tip(tip_percentage)
And to get the grand total:
grand_total = b.calculate_total(tip_percentage)
Your original class, for reference, looks like:
class Tip:
def __init__(self,sub_total,percentage):
self.tip= (sub_total * percentage)
def __str__(self):
return 'Tip['+str(sub_total)+' * '+str(percentage)+']'
def sub_total():
sub_total = input()
def percentage():
percentage = input()
def get_tip(percentage, sub_total):
percentage = decimal.Decimal(percentage)
sub_total = decimal.Decimal(sub_total)
tip = ((sub_total * percentage) / 100)
total = (sub_total + tip)
return Tip(total)
We'll talk about it method by method.
__init__
This one is great! It means you create a Tip
object by passing the sub_total and the percentage (as a ratio to 1) in the constructor, so t = Tip(15.00, 0.15)
is a 15% tip on $15. Hooray!
__str__
Only briefly going to go into this one, other than to mention that this looks more like a __repr__
than a __str__
and you should use (
/)
instead of [
/]
. Remember that sub_total
and percentage
aren't attributes of the object -- they're just arguments that were passed to its constructor. You can't reference them here if you don't save them in the __init__
method.
sub_total
First of all, you can't call this since it doesn't have a self
argument. Second of all it doesn't do anything even if you could. sub_total = input()
gets user input, then throws it away.
percentage
See above
get_tip
You're missing a self
argument, again, but I'll talk about it as if it was get_tip(self, percentage, sub_total)
. You call this by using your already-created Tip
object (remember above when we did t = Tip(15, 0.15)
?) and calling it with the arguments that you probably passed the constructor. In other words:
t = Tip(15, 0.15) # 15% tip on $15
t.get_tip(0.15, 15) # ...15% tip on $15, but the grand total...
It doesn't make a whole lot of sense as a function. Especially since half your work is already done for you and saved in self.tip
. If this is the pattern you wanted to use for your object, you could do something like:
class Tip(object):
def __init__(self, sub_total, tip_pct):
self.sub_total = sub_total
self.tip_pct = tip_pct
# saving these as attributes so we can use them later
self.grand_total = self.sub_total * (1 + self.tip_pct)
self.tip_amt = self.sub_total * self.tip_pct
But that really looks more like a series of functions to me, than something that needs to be saved as an object!
Remember that classes are here to provide a state for your code to run in. In this case, the only state you can really apply is "How much to tip," so I suppose you could do the reverse of this and do something like:
t = Tip(0.15)
t.calculate_total(amt_of_bill)
But it seems silly to me. You could maybe make a factory function that does something like:
def tip(tip_pct):
def wrapped(bill_amt):
return bill_amt * (1 + tip_pct)
return wrapped
But that's a little advanced for where you're at.