Keeping the object valid
The code that uses an object is called its client. The client asks the object to do things by calling its methods. That gives the methods a chance to make sure that the object's state always makes sense: a stock count is never negative, a volume knob stays between its lowest and highest setting.
Here is a counter that counts down but never goes below zero, not even when it is made with a negative number:
class Countdown:
def __init__(self, start):
self.value = 0
if start > 0:
self.value = start
def decrease(self):
if self.value > 0:
self.value -= 1
timer = Countdown(2)
for i in range(4):
timer.decrease()
print(timer.value)
broken = Countdown(-5)
print(broken.value)
1
0
0
0
0A method that can't do what was asked can also tell the client so, by returning True or False:
class Stock:
def __init__(self, item, amount):
self.item = item
self.amount = amount
def take(self, count):
if count <= self.amount:
self.amount -= count
return True
return False
paint = Stock("paint can", 5)
print(paint.take(3), paint.amount)
print(paint.take(3), paint.amount)
True 2
False 2The second time, there aren't enough cans, so take changes nothing and returns False. The client can then decide what to do, such as print a message.
When a request makes no sense at all, the method can raise an error, as you learned in part 6:
class Stock:
def __init__(self, item, amount):
self.item = item
self.amount = amount
def add(self, count):
if count < 0:
raise ValueError("count can't be negative")
self.amount += count
paint = Stock("paint can", 5)
paint.add(4)
print(paint.amount)
paint.add(-10)
9Traceback (most recent call last):
File "main.py", line 15, in <module>
paint.add(-10)
~~~~~~~~~^^^^^
File "main.py", line 8, in add
raise ValueError("count can't be negative")
ValueError: count can't be negativeEncapsulation
Keeping an object's data valid by handling it only through the object's methods is called encapsulation. The client calls take and add and doesn't need to know how the stock is kept inside the object.
Python doesn't force this, though: a client can still write paint.amount = -10, and nothing stops it. The methods protect the object only when the client uses them. The Encapsulation module in part 9 shows how a class can hide its attributes; until then, change an object's state through its methods.