Python Arena
Step 3 of 4

A class that keeps a list

Many classes keep a collection of things in a list attribute and offer methods to add to it, take from it and ask about it. The client doesn't touch the list itself; it uses the methods.

The string method join from part 4 comes in handy for showing such a list. As a reminder, it puts the strings of a list together into one string, with the string it is called on between them:

In the Python interpreter
>>> names = ["Ann", "Bo", "Cy"]
>>> ", ".join(names)
'Ann, Bo, Cy'
>>> " / ".join(names)
'Ann / Bo / Cy'

Read ", ".join(names) as "join the names with a comma and a space". All the items have to be strings.

Here is a waiting list for a busy restaurant. The first to arrive is the first to get a table:

class WaitingList:
    def __init__(self):
        self.names = []

    def add(self, name):
        self.names.append(name)

    def next_up(self):
        return self.names.pop(0)

    def size(self):
        return len(self.names)

    def __str__(self):
        if len(self.names) == 0:
            return "nobody waiting"
        return ", ".join(self.names)


tables = WaitingList()
tables.add("Ann")
tables.add("Bo")
tables.add("Cy")
print(tables)
print("Table for", tables.next_up())
print(tables, "/", tables.size(), "waiting")
Output
Ann, Bo, Cy
Table for Ann
Bo, Cy / 2 waiting

next_up both changes the list and returns the name it took out, thanks to pop(0). The constructor makes a new empty list for every waiting list, so two restaurants never share one.

A list of tuples

When each thing in the collection has several pieces of data, the list can hold tuples. This playlist keeps each song as a pair of its title and its length in seconds:

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

    def add(self, title, seconds):
        self.songs.append((title, seconds))

    def total_seconds(self):
        total = 0
        for title, seconds in self.songs:
            total += seconds
        return total

    def longest(self):
        best = self.songs[0]
        for song in self.songs:
            if song[1] > best[1]:
                best = song
        return best[0]

    def __str__(self):
        titles = []
        for title, seconds in self.songs:
            titles.append(title)
        return f"{self.name}: " + ", ".join(titles)


road_trip = Playlist("Road trip")
road_trip.add("Highway Song", 215)
road_trip.add("Desert Wind", 342)
road_trip.add("Gas Station Blues", 187)
print(road_trip)
print(road_trip.total_seconds(), "seconds")
print("Longest:", road_trip.longest())
Output
Road trip: Highway Song, Desert Wind, Gas Station Blues
744 seconds
Longest: Desert Wind

for title, seconds in self.songs: takes each tuple apart into two variables, as you did with a dictionary's items(). In longest, song[1] is a song's length and best[0] the title of the longest one.

Your task

Challenge 1 of 3

Fill in the blanks, so that the bag keeps its items in a list and the program prints:

keys, phone, apple

Challenge 2

Write a class Cart for a web shop's shopping cart. It keeps the products and their prices in a list. Give it these methods:

  • add(product, price) puts a product in the cart.
  • remove(product) takes the first product with that name out of the cart and returns True, or returns False when there is none.
  • total() returns the sum of the prices.
  • __str__ returns the number of items and the total with two decimals, in the form shown below.

This code:

cart = Cart()
cart.add("socks", 4.5)
cart.add("hat", 12)
cart.add("socks", 4.5)
print(cart)
print(cart.remove("hat"), cart.remove("scarf"))
print(cart)

prints

items: 3, total 21.00
True False
items: 2, total 9.00

Challenge 3

Write a class TicketQueue for the line at a ticket counter. Give it these methods:

  • arrive(name) puts the person at the end of the line.
  • serve() takes the first person out of the line and returns their name. When the line is empty, it returns the string "nobody".
  • position(name) returns the person's place in the line, counting from 1, or 0 when they are not in it.
  • __str__ returns the names in order with > between them, or empty when nobody is waiting.

This code:

line = TicketQueue()
line.arrive("Ann")
line.arrive("Bo")
line.arrive("Cy")
print(line)
print(line.position("Cy"), line.position("Dee"))
print(line.serve())
print(line)

prints

Ann > Bo > Cy
3 0
Ann
Bo > Cy