Comet has a new idea for turn_right(). "A dict that says what comes after each heading," she says. "No index, no %. Just look it up!"
Wren holds up drive_test.py. "What does the evidence say?" he asks. "If you change turn_right() inside, will this driver still work without one change?"
Nova projects rover.py with only the inside of one method glowing. "How can I help?" she asks. "Change the glowing part. Then run the same driver and compare."
Comet cracks her knuckles. "Lead programmer, let's find out."
Procedural abstraction gives a process a name, so you can use a method knowing what it does, not how it does it.
Its insides can change without telling the callers, as long as the method signature and what it does stay the same.
Comet's version keeps the name and the job of turn_right(), and changes only how it works:
RIGHT_OF = {"N": "E", "E": "S", "S": "W", "W": "N"}
def turn_right(self):
self._heading = RIGHT_OF[self._heading] In IDLE, open rover.py and choose File, then Save As, to save a copy called rover_dict.py. Make Comet's change in that copy only.
# drive_dict.py
from rover_dict import Rover
pip = Rover("Pip")
print(pip.status())
pip.turn_right()
print(pip.get_heading())
pip.turn_right()
pip.turn_right()
pip.turn_right()
print(pip.get_heading())
pip.turn_left()
print(pip.status())
print(Rover.rovers_built) Pip at (0, 0) facing E, battery 100 S E Pip at (0, 0) facing N, battery 100 1
Inside turn_left(), the name i is made each time the method runs. Does it exist outside the method? What does a mutator give back?
# local_demo.py
from rover import Rover
pip = Rover("Pip")
print(pip.turn_left())
print(pip.get_heading())
print(i) None
N
Traceback (most recent call last):
File "local_demo.py", line 7, in <module>
print(i)
^
NameError: name 'i' is not defined. Did you mean: 'id'? # turn_drill.py
from rover import Rover
pip = Rover("Pip")
for c in "RRLRR":
if c == "R":
pip.turn_right()
else:
pip.turn_left()
print(pip.get_heading()) | Command | Heading after it |
|---|---|
| (start) | E |
| R | S |
| R | W |
| L | S |
| R | W |
| R | N |
# test_rover.py
from rover import Rover
def test_start():
r = Rover("Test")
assert r.get_heading() == "E"
assert r.get_battery() == 100
def test_turns():
r = Rover("Test")
for n in range(4):
r.turn_right()
assert r.get_heading() == "E"
r.turn_left()
assert r.get_heading() == "N"
test_start()
test_turns()
print("All Rover tests passed") Same outside, new inside, and every caller still works. Tomorrow is Mission Quest: design a class at home.