Python Composition · Exercises
Object-Oriented Python

Python Composition Exercises

4 exercises that build on the Python Composition: Has-A vs Is-A lesson, from easy to hard. Each one is checked in your browser when you press Check. Stuck? Use the hint before peeking at the solution.

What this lesson covers: Composition means building a class out of other objects it holds as attributes (a Car has an Engine) and delegating work to them, instead of inheriting from them; use inheritance for "is-a" relationships and composition for "has-a" ones. By the end you can decide between "is-a" and "has-a", store other objects as attributes, delegate work to them, swap parts without changing the outer class, keep a list of child objects with aggregate methods, and refactor a wrong inheritance into composition. You will practise: Give a Laptop a Battery; Predict the shared song; Fix the orders that share their lines; A cart with a swappable discount.

0 / 4 completed

Python Composition practice exercises

1. Give a Laptop a Battery

Write code Easy

Battery is given. Write a class Laptop that has a battery:

  • __init__(self, model, battery) stores both on self (as model and battery).
  • work(self, hours) delegates to the battery by calling self.battery.drain(...) with hours * 15.
  • charge_left(self) returns the battery's level.
Your code
class Battery:
    def __init__(self, level=100):
        self.level = level

    def drain(self, amount):
        self.level = max(0, self.level - amount)

# Write class Laptop below.

2. Predict the shared song

Predict the output Medium

Two playlists hold the same Song object. Think about what a list stores (the object itself, not a copy) and type exactly what the program prints.

Read this code
class Song:
    def __init__(self, title):
        self.title = title

class Playlist:
    def __init__(self, name):
        self.name = name
        self.songs = []

    def add(self, song):
        self.songs.append(song)

    def titles(self):
        return [song.title for song in self.songs]

hit = Song("Sunrise")
gym = Playlist("Gym")
trip = Playlist("Trip")
gym.add(hit)
trip.add(hit)
trip.add(Song("Highway"))
hit.title = "Sunrise (remix)"
print(gym.titles())
print(trip.titles())
print(len(gym.songs), len(trip.songs))

3. Fix the orders that share their lines

Fix the bug Medium

Each Order should have its own list of order lines. The program should print 3.0 12.0, but Ben's order also contains Asha's pen, so it prints 15.0 15.0. Fix the Order class.

Your code
class OrderLine:
    def __init__(self, product, price, quantity):
        self.product = product
        self.price = price
        self.quantity = quantity

    def subtotal(self):
        return self.price * self.quantity

class Order:
    def __init__(self, customer, lines=[]):
        self.customer = customer
        self.lines = lines

    def add(self, product, price, quantity=1):
        self.lines.append(OrderLine(product, price, quantity))

    def total(self):
        return sum(line.subtotal() for line in self.lines)

first = Order("Asha")
first.add("pen", 1.5, 2)
second = Order("Ben")
second.add("book", 12.0)
print(first.total(), second.total())

4. A cart with a swappable discount

Write code Hard

Item, PercentOff and FlatOff are given. Write a class Cart that has a list of items and an optional discount object:

  • Cart(discount=None) stores discount and a new empty list items.
  • add(item) appends an item.
  • total() adds up the item prices. If there is a discount, pass the sum to self.discount.apply(amount) and use the result. Return the final amount rounded to 2 decimals.

Cart must work with any object that has an apply(amount) method.

Your code
class Item:
    def __init__(self, name, price):
        self.name = name
        self.price = price

class PercentOff:
    def __init__(self, percent):
        self.percent = percent

    def apply(self, amount):
        return amount * (100 - self.percent) / 100

class FlatOff:
    def __init__(self, off):
        self.off = off

    def apply(self, amount):
        return max(0, amount - self.off)

# Write class Cart below.

Next lessonPython Abstract Classes (ABC)

More Python Composition: Has-A vs Is-A examples · All Python exercises