Changing State

Changing State

Methods can change an object's attributes, not only read them. The attributes at any moment are the object's state:

class Thermostat:
    def __init__(self, target):
        self.target = target

    def raise_by(self, degrees):
        self.target += degrees

    def lower_by(self, degrees):
        self.target -= degrees

Each call updates the object, and the change persists:

t = Thermostat(20)
t.raise_by(3)
t.lower_by(1)
print(t.target)

Output:

22

This is the accumulator pattern moved into an object: instead of a variable updated by loop passes, an attribute updated by method calls. Methods that change state usually return nothing — the result is the new state, read from the attribute.

A state-changing method can also enforce rules with raise, refusing changes that would make the state invalid.

Exercise

  1. Define a class named Odometer.
  2. __init__ takes no arguments besides self and sets a kilometers attribute to 0.
  3. Add a method named drive with one parameter, distance. It adds distance to kilometers. If distance is negative, raise ValueError with the message distance cannot be negative and leave the state unchanged.

Run your code to see the output, then press Submit.

Tests

import unittest


class TestOdometer(unittest.TestCase):
    def test_starts_at_zero(self):
        self.assertEqual(Odometer().kilometers, 0)

    def test_drives_accumulate(self):
        odometer = Odometer()
        odometer.drive(120)
        odometer.drive(35)
        self.assertEqual(odometer.kilometers, 155)

    def test_negative_distance_raises(self):
        odometer = Odometer()
        with self.assertRaises(ValueError):
            odometer.drive(-5)

    def test_state_is_unchanged_after_a_rejected_drive(self):
        odometer = Odometer()
        odometer.drive(10)
        try:
            odometer.drive(-5)
        except ValueError:
            pass
        self.assertEqual(odometer.kilometers, 10)
class Odometer:
    def __init__(self):
        self.kilometers = 0

    def drive(self, distance):
        if distance < 0:
            raise ValueError("distance cannot be negative")
        self.kilometers += distance


odometer = Odometer()
odometer.drive(120)
odometer.drive(35)
print(odometer.kilometers)
Solution hidden. Give it a real try first.

Sign in to join the discussion.

No comments yet. Be the first to ask a question.

main.py
Console
Press Run to execute your code, or Submit to test and complete this problem.