Helper methods and local variables
As a class grows, some of its methods are there only to help the others. A helper method is called through self, from the constructor or from another method. This booking class checks its arguments with one:
class Booking:
def __init__(self, name, guests, nights):
self.name = name
self.guests = 1
self.nights = 1
if self.in_range(guests, 8):
self.guests = guests
if self.in_range(nights, 30):
self.nights = nights
def in_range(self, number, largest):
return 1 <= number <= largest
def price(self):
per_night = 50 + 20 * (self.guests - 1)
return per_night * self.nights
kim = Booking("Kim", 3, 2)
lee = Booking("Lee", 12, 0)
print(kim.guests, kim.nights, kim.price())
print(lee.guests, lee.nights, lee.price())
3 2 180
1 1 50The constructor first gives every attribute a safe value, then uses self.in_range to decide whether the arguments can replace them. Lee's booking had impossible numbers, so it keeps the safe ones. Forget the self. in front of a helper method, and Python stops with NameError: name 'in_range' is not defined. Did you mean: 'self.in_range'?
Local variables
Look at per_night in price. It has no self. in front, so it is an ordinary local variable: it exists only while the method runs, like a variable inside any function. Use attributes for what the object must remember from one call to the next, and local variables for the steps of a calculation.
What an object needs to remember
An object doesn't have to keep a record of everything that happens to it, only what its methods need. A habit tracker that reports your current streak (how many days in a row you have practiced, up to the last one) and your longest streak needs two numbers, not a list of every day:
class Streak:
def __init__(self):
self.current = 0
self.longest = 0
def log(self, done):
if done:
self.current += 1
if self.current > self.longest:
self.longest = self.current
else:
self.current = 0
guitar = Streak()
while True:
answer = input("Practiced today? ")
if answer == "":
break
guitar.log(answer == "yes")
print("Current streak:", guitar.current)
print("Longest streak:", guitar.longest)
yes
yes
yes
no
yes
(an empty line)Practiced today? yes
Practiced today? yes
Practiced today? yes
Practiced today? no
Practiced today? yes
Practiced today?
Current streak: 1
Longest streak: 3Each call of log keeps both numbers up to date: a day of practice makes the current streak one longer, and the longest one too if it was just beaten, and a day off starts the current streak again from 0. The main program only reads the answers and hands each one to the object. answer == "yes" is already True or False, just what log expects.