Lesson 26 of 35Python
Python · Lesson 26 · 30 minutes
Special methods and @property
What you'll learn
- Decide with
__str__howprint()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))| Notation | calls |
|---|---|
print(a), str(a) | a.__str__() |
a + b | a.__add__(b) |
a == b | a.__eq__(b) |
a < b | a.__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()orlen().
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)- Something to think about
Write
__str__and returnf"{self.minutes}:{self.seconds:02d}"– :02d makes two-digit numbers. - Which command helps?
Write
@propertyabove a methodtotal(self)that returns minutes*60+seconds.__add__should return a NEW time, e.g.Time(0, self.total + other.total).__lt__(self, other)returnsTrueifself.totalis smaller thanother.total. - Gap code – fill in the ___
class Time: def __init__(self, minutes, seconds): self.minutes = minutes + seconds // 60 self.seconds = seconds % 60 def __str__(self): return ___ ___ def total(self): return ___ def __add__(self, other): return ___ def __lt__(self, other): return ___ 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🔒 Unlocks after all hints or 2 checks
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)