← Back to course
Python 11-12 / Week 04 / Wednesday
3/6
Week 04 · Objects Working Together

Wednesday

Sim Lab: Pip carries samples
// Names, references and objects that hold objects
⏱ about 30 min

Wednesday: Sim Lab: Pip Carries Samples

Comet sets four sample tokens on the workbench. "Pip drives to a spot and picks up the sample there," she says. "Let's give the Rover class a place to keep them."

Wren checks the field sketch. "What does the evidence say about room?" he asks. "Pip's tray has three slots. What happens on the fourth sample?"

"It should say no," Comet says. "Calmly. Nothing breaks."

Nova projects a tray with three empty slots above the desk. "How can I help?" she asks. "Build it in stages. Predict before every run."

Comet slides the keyboard over. "Lead programmer, the rover file is yours today."

The plan

Today rover.py grows. A Rover gets two new instance variables: _capacity, set to 3, and _samples, an empty list.

An object's state is its attributes and their values, and the object has a has-a relationship with them. A Rover now has samples.

A constructor sets the starting state, with a starting value for every instance variable. So both new variables go in __init__.

Below the plan are __init__ after the change and the first two new methods.

MethodChanges Pip?What it does
pick_up(sample)yes (a mutator)Adds the sample if there is room. Gives back True or False.
get_samples()no (an accessor)Gives back a copy of the list of samples.
total_grams()noAdds up the grams of the samples Pip holds.
  1. Open rover.py from your fieldsim folder. Before you change it, save a copy named rover_w3.py. That copy is your snapshot.
  2. In __init__, add the two lines for _capacity and _samples, just before Rover.rovers_built += 1.
  3. At the end of the class, add pick_up and get_samples. Keep the 4-space indents.
  4. Save. Make carry_two.py in the same folder, predict, then run it.
  5. Add total_grams to the class and save. Make carry.py, predict, then run it.
    def __init__(self, name, row=0, col=0):
        self.name = name
        self._row = row
        self._col = col
        self._heading = "E"
        self._battery = 100
        self._capacity = 3
        self._samples = []
        Rover.rovers_built += 1
    def pick_up(self, sample):
        """Add a sample if there is room. Gives back True or False."""
        if len(self._samples) >= self._capacity:
            return False
        self._samples.append(sample)
        return True

    def get_samples(self):
        return list(self._samples)
# carry_two.py
from rover import Rover
from sample import Sample

pip = Rover("Pip")
print(pip.pick_up(Sample("S01", "basalt", 42, 0, 2)))
print(pip.pick_up(Sample("S02", "quartz", 18, 2, 4)))
print(len(pip.get_samples()), "samples")
print(pip.status())
PREDICT BEFORE RUN 1: CARRY_TWO.PY
  • Read the question.
  • Tap your answer.
What does the third line show?
What does the last line show?
True
True
2 samples
Pip at (0, 0) facing E, battery 100

Now add the last new method:

    def total_grams(self):
        total = 0
        for s in self._samples:
            total += s.grams
        return total
# carry.py
from rover import Rover
from sample import Sample

pip = Rover("Pip")
spots = [
    Sample("S01", "basalt", 42, 0, 2),
    Sample("S02", "quartz", 18, 2, 4),
    Sample("S03", "clay", 65, 3, 0),
    Sample("S04", "mica", 7, 4, 5),
]
for s in spots:
    print(s.label, pip.pick_up(s))
print(len(pip.get_samples()), "samples")
print("Total:", pip.total_grams(), "g")
PREDICT BEFORE RUN 2: CARRY.PY
  • Read the question.
  • Tap your answer.
What does the S04 line show?
What does the Total line show?
S01 True
S02 True
S03 True
S04 False
3 samples
Total: 125 g

Change it once, break it once

Change self._capacity = 3 to self._capacity = 4 in rover.py, save, and run carry.py again.

PREDICT: CAPACITY 4
  • Read the question.
  • Tap your answer.
With capacity 4, what does the Total line show?
S01 True
S02 True
S03 True
S04 True
4 samples
Total: 132 g

Set it back to 3. Then break total_grams on purpose: change self._samples to self._sample in its for line. Save and run carry.py.

S01 True
S02 True
S03 True
S04 False
3 samples
Traceback (most recent call last):
  File "carry.py", line 15, in <module>
    print("Total:", pip.total_grams(), "g")
                    ~~~~~~~~~~~~~~~^^
  File "rover.py", line 58, in total_grams
    for s in self._sample:
             ^^^^^^^^^^^^
AttributeError: 'Rover' object has no attribute '_sample'. Did you mean: '_samples'?
What kind of error stops carry.py?
Which name does Python suggest you meant?
At your computer
1. Fix the typo: change self._sample back to self._samples. Save and run carry.py once more.
2. Check that the six lines are back, ending with Total: 125 g. Capacity stays at 3 from now on.
3. Keep rover_w3.py as your snapshot. rover.py is now the week 4 version.

Pip can carry samples now. Tomorrow you will see why get_samples hands out a copy.

← Tuesday