Python Arena
Step 3 of 4

Objects as arguments

A function can change the object it gets

You have written functions that change an object they get. Now you can see why that works: when you call a function with an object, the parameter refers to the same object as the argument. Nothing is copied. So when the function changes the object's attributes, the caller sees the change after the call, just as with lists in the References module:

class Hero:
    def __init__(self, name):
        self.name = name
        self.level = 1

    def __str__(self):
        return f"{self.name} (level {self.level})"


def level_up(hero):
    hero.level += 1


ayla = Hero("Ayla")
print(ayla)
level_up(ayla)
level_up(ayla)
print(ayla)
Output
Ayla (level 1)
Ayla (level 3)

During the call, hero inside the function and ayla outside it are two names for one object.

There is one catch. Giving the parameter a new value inside the function, such as hero = Hero("Bram"), only makes the local name refer to another object. The caller's variable still refers to the old one. To change the caller's object, change its attributes.

A function can create an object

A function can also create a new object and return it. The caller gets a reference to it, and can keep it in a variable or a list. This function turns a line of text into a Hero:

class Hero:
    def __init__(self, name):
        self.name = name
        self.level = 1

    def __str__(self):
        return f"{self.name} (level {self.level})"


def hero_from_text(line):
    parts = line.split(";")
    hero = Hero(parts[0])
    hero.level = int(parts[1])
    return hero


team = []
for line in ["Ayla;3", "Bram;5"]:
    team.append(hero_from_text(line))

for hero in team:
    print(hero)
Output
Ayla (level 3)
Bram (level 5)

The object created inside the function lives on after the function ends, because the caller still has a reference to it.

A method can take an object too

Methods are functions that belong to a class, so they can take objects as arguments as well. A method that gets an object of another class can read and change that object, and its own object at the same time. Here a coach trains athletes: training makes the athlete faster, and the coach counts the sessions.

class Athlete:
    def __init__(self, name, speed):
        self.name = name
        self.speed = speed


class Coach:
    def __init__(self, name, boost):
        self.name = name
        self.boost = boost
        self.sessions = 0

    def train(self, athlete):
        athlete.speed += self.boost
        self.sessions += 1
        print(f"{self.name} trained {athlete.name}, speed now {athlete.speed}")


mia = Athlete("Mia", 20)
tom = Athlete("Tom", 25)
ray = Coach("Coach Ray", 3)
ray.train(mia)
ray.train(mia)
ray.train(tom)
print("Sessions:", ray.sessions)
Output
Coach Ray trained Mia, speed now 23
Coach Ray trained Mia, speed now 26
Coach Ray trained Tom, speed now 28
Sessions: 3

Inside train, self is the coach the method is called on (the object before the dot), and athlete is the athlete in the parentheses. One call, ray.train(mia), changes both objects: Mia's speed and Ray's count of sessions.

Your task

Challenge 1 of 3

A library lends books. Fill in the blanks in the method lend, so that it marks the book as lent and counts the loans of the library. The program should print:

World Atlas lent out
World Atlas is already on loan
Cookbook lent out
Loans: 2

Challenge 2

Write a function parse_book(line). It gets a line of text with a book's title, author and number of pages, separated by semicolons, such as "The Quiet Sea;Ana Lind;318", and returns a new Book object made from it. The number of pages must be a number (an int), not text.

For example, this code:

book = parse_book("The Quiet Sea;Ana Lind;318")
print(book)
print(book.pages + 1)

prints:

The Quiet Sea by Ana Lind, 318 pages
319

Challenge 3

A ferry has room for cars up to a total length in meters. Write the method board(self, car) in the class Ferry:

  • If the car fits in the space that's left, it boards: the ferry's space_left goes down by the car's length, its cars goes up by one, and the method returns True.
  • If the car doesn't fit, nothing changes and the method returns False.

For example, this code:

ferry = Ferry(10)
print(ferry.board(Car("ABC-123", 4)))
print(ferry.board(Car("XYZ-789", 7)))
print(ferry)

prints:

True
False
cars: 1, space left: 6 m