Skip to content
BetaDE
Lesson 26 of 35Python

Python · Lesson 26 · 30 minutes

Special methods and @property

What you'll learn

  • Decide with __str__ how print() shows an object
  • Compare and calculate with objects using __eq__, __lt__ and __add__
  • Write calculated attributes with @property

Objects that behave like built-in types

You can add numbers with + and compare them with <, and print() shows them nicely. With special methods (they have two underscores before and after, which is why they’re also called “dunder” methods) your own classes can do that too.

str: what does my object look like?

Without __str__, print() only shows something like <__main__.Point object at 0x…>. With __str__ you decide the text yourself:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"({self.x}|{self.y})"

p = Point(3, 4)
print(p)
print(f"The point is at {p}.")

Calculating and comparing

a + b actually calls a.__add__(b), a == b calls a.__eq__(b) and a < b calls a.__lt__(b):

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __str__(self):
        return f"({self.x}|{self.y})"

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

print(Point(1, 2) + Point(10, 20))
print(Point(1, 2) == Point(1, 2))
Notationcalls
print(a), str(a)a.__str__()
a + ba.__add__(b)
a == ba.__eq__(b)
a < ba.__lt__(b)
len(a)a.__len__()

@property: calculated attributes

Some values are better calculated than stored. With @property a method looks like a normal attribute from the outside – without brackets:

class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height

    @property
    def area(self):
        return self.width * self.height

r = Rectangle(4, 3)
print(r.area)
r.width = 10
print(r.area)

The area adjusts automatically when the width changes.

Remember: You hardly ever call special methods yourself. Python calls them for you when you use +, <, print() or len().

Quick check

Before you start the task: what does this program print? Type your guess – then Python works it out.

class Point:
    def __init__(self, x, y):
        self.x, self.y = x, y

    def __str__(self):
        return f"({self.x}|{self.y})"

    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)


print(Point(1, 2) + Point(3, 4))

Your task

Your turn

Complete the class Time (minutes and seconds). print() should show it like 2:05 (seconds always with two digits). Two times should add up with + (90 seconds become 1 minute 30 seconds), compare with <, and the attribute total (with @property) should give the time in seconds.

class Time:
    def __init__(self, minutes, seconds):
        self.minutes = minutes + seconds // 60
        self.seconds = seconds % 60

    # __str__, @property total, __add__, __lt__


lap1 = Time(1, 40)
lap2 = Time(0, 85)
print(lap1 + lap2)
print(lap2 < lap1)

Solve it without hints to earn a ⭐ on your progress page.

Show solution

Try it yourself first – mistakes teach you the most. Here is one possible solution:

class Time:
    def __init__(self, minutes, seconds):
        self.minutes = minutes + seconds // 60
        self.seconds = seconds % 60

    def __str__(self):
        return f"{self.minutes}:{self.seconds:02d}"

    @property
    def total(self):
        return self.minutes * 60 + self.seconds

    def __add__(self, other):
        return Time(0, self.total + other.total)

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


lap1 = Time(1, 40)
lap2 = Time(0, 85)
print(lap1 + lap2)
print(lap2 < lap1)