28. Many objects together

Chapters 26 and 27 built one object at a time. Classes shine with many objects of one kind treated as a group: a party of characters, a swarm of enemies. This chapter combines two things you know — a class (Chapter 27) and a list (Chapter 22) — into the everyday pattern of a list of objects.

A class to make many of

A small Critter class — a constructor and two methods, the Chapter 27 pattern.

class Critter:
    def __init__(self, name, energy):
        self.name = name
        self.energy = energy

    def play(self):
        self.energy = self.energy - 1
        print(f"{self.name} plays. Energy: {self.energy}")

    def is_tired(self):
        return self.energy <= 0

Put the objects in a list

Each Critter(...) call returns a fresh instance. Store several in a list, like any value:

critters = [
    Critter("Spark", 3),
    Critter("Bolt", 2),
    Critter("Nova", 1),
]

critters is a normal list (Chapter 22). What's new is that each item is an object with its own state and methods.

Loop and call a method on each

Walk the list with a for loop and call a method on each object. Each acts on its own data:

for c in critters:
    c.play()

Output:

Spark plays. Energy: 2
Bolt plays. Energy: 1
Nova plays. Energy: 0

One loop, three objects, three separate energies. This is the core move of object-oriented code: keep a collection, act on it as a group, and let each object track itself.

Open exercises/28/01-critters.py. It builds a list of critters and makes each play once. Add a second loop so each plays again, and watch the energies drop.

Filtering and counting objects

Because it's just a list, every Chapter 20 loop pattern works on objects too. Count how many critters are tired:

tired = 0
for c in critters:
    if c.is_tired():
        tired = tired + 1
print(f"{tired} critters need a rest.")   # 1 critters need a rest.

The if calls a method (c.is_tired()) instead of testing a plain field, but the count pattern is unchanged.

Adding and removing objects

list.append() and list.pop() (Chapter 24) work on a list of objects just like a list of numbers:

critters.append(Critter("Zip", 5))   # a new critter joins
critters.pop(0)                      # the first one leaves

Objects are values like any other — added, removed, sorted, and counted.

Homework

Homework files are in exercises/28/homework/.

Problem 1 — A party of heroes

Open exercises/28/homework/01-party.py. A small Hero class is provided. Create a list of three heroes with different names and hit points, then loop over the list and print each one's name and HP on its own line.

Problem 2 — Total HP

Open exercises/28/homework/02-total-hp.py. Use the accumulate pattern to add up everyone's HP and print the team total.

Problem 3 — Who is hurt?

Open exercises/28/homework/03-who-is-hurt.py. Each hero has an hp and a max_hp. Loop over the party and print every hero whose hp is below max_hp.

Challenge — Strongest hero

Open exercises/28/homework/04-strongest.py. Loop over the party and print the name of the hero with the most HP. Use the accumulate-a-maximum idea: remember the best so far, replacing it when you find a stronger one.

Stuck or finished? Open the homework solutions page.