Python Arena
Step 1 of 5

Comparing objects with operators

A method can return an object, including an object of its own class. And since self is the object itself, a method can return self too. Here heavier compares two parcels and returns the heavier one, whichever it is:

class Parcel:
    def __init__(self, label, weight):
        self.label = label
        self.weight = weight

    def __str__(self):
        return f"{self.label} ({self.weight} kg)"

    def heavier(self, other):
        if self.weight > other.weight:
            return self
        return other


books = Parcel("Books", 12)
pillow = Parcel("Pillow", 2)
print(books.heavier(pillow))
print(pillow.heavier(books))
Output
Books (12 kg)
Books (12 kg)

That works, but it would be nicer to compare parcels the way you compare numbers, with > and <. As it is, Python doesn't know how:

class Parcel:
    def __init__(self, label, weight):
        self.label = label
        self.weight = weight


books = Parcel("Books", 12)
pillow = Parcel("Pillow", 2)
print(books > pillow)
Python stops with
Traceback (most recent call last):
  File "main.py", line 9, in <module>
    print(books > pillow)
          ^^^^^^^^^^^^^^
TypeError: '>' not supported between instances of 'Parcel' and 'Parcel'

Operator overloading

A class can decide what an operator means for its objects. This is called operator overloading. Each operator has a method with a special name, with two underscores on both sides, like __init__ and __str__. When Python meets a > b and a is an object of your class, it calls a.__gt__(b) ("gt" for greater than). The method returns True or False:

class Parcel:
    def __init__(self, label, weight):
        self.label = label
        self.weight = weight

    def __str__(self):
        return f"{self.label} ({self.weight} kg)"

    def __gt__(self, other):
        return self.weight > other.weight

    def __lt__(self, other):
        return self.weight < other.weight


books = Parcel("Books", 12)
pillow = Parcel("Pillow", 2)
lamp = Parcel("Lamp", 5)
print(books > pillow)
print(books < pillow)

parcels = [books, pillow, lamp]
for parcel in sorted(parcels):
    print(parcel)
print("Heaviest:", max(parcels))
Output
True
False
Pillow (2 kg)
Lamp (5 kg)
Books (12 kg)
Heaviest: Books (12 kg)

You decide what "greater" means. Here it's the weight; for another class it could be a price, a date, or the alphabetical order of names. And there's a bonus: sorted, min and max compare items with < and >, so they work with your objects too, as soon as the class has these methods.

These are the comparison operators and their methods:

Operator Meaning Method
< less than __lt__(self, other)
> greater than __gt__(self, other)
<= less than or equal to __le__(self, other)
>= greater than or equal to __ge__(self, other)
== equal to __eq__(self, other)
!= not equal to __ne__(self, other)

You only need to write the ones that make sense for your class. The next step looks at ==, which works a little differently.

Your task

Challenge 1 of 3

The faster runner is the one with fewer seconds. Fill in the blank with the name of the method that makes < work for runners, so the program prints:

True
False

Challenge 2

A room is bigger than another when its floor area, width times length, is bigger. Add the methods __lt__ and __gt__ to the class Room, so that rooms can be compared with < and >, and max finds the biggest room. For example,

kitchen = Room("Kitchen", 3, 4)
hall = Room("Hall", 2, 5)
print(kitchen > hall)
print(kitchen < hall)
print(hall < kitchen)
print(max([hall, kitchen]).name)

should print:

True
False
True
Kitchen

Challenge 3

A color on a screen is made of red, green and blue light, each a whole number from 0 to 255. Add two methods to the class Color. Both return a new color and leave the original as it is:

  • mix(other) returns a color whose red is the average of the two colors' reds, rounded down, and the same for green and blue.
  • brighter() returns a color with 50 more of each, but never more than 255. (min works with two numbers too: min(a, b) is the smaller of them.)

For example,

red = Color(255, 0, 0)
blue = Color(0, 0, 255)
print(red.mix(blue))
print(red.brighter())
print(red)

should print:

rgb(127, 0, 127)
rgb(255, 50, 50)
rgb(255, 0, 0)