Operator overloading in Python beheersen: een praktische gids
Python Operator Overloading
Ontdek hoe je operatorgedrag in Python kunt herdefiniëren met speciale methoden zoals __add__, __lt__ en meer, om je OOP-ontwerpen te verbeteren.
Python Operator Overloading
Python's ingebouwde operators werken verschillend afhankelijk van operand-typen. De +-operator telt getallen op, concateneert strings of mergt lijsten. Deze flexibiliteit wordt bereikt via operator overloading – een feature die je context-specifieke betekenissen aan operators toewijst voor je eigen klassen.
Overweeg een simpele Punt-klasse die een coördinaat in een 2-D vlak vertegenwoordigt. Zonder speciale methoden zal het proberen om twee punten op te tellen een TypeError opleveren:
class Punt:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
p1 = Punt(1, 2)
p2 = Punt(2, 3)
print(p1+p2)
Uitvoer
Traceback (most recent call last): File "<string>", line 9, in <module> print(p1+p2) TypeError: unsupported operand type(s) for +: 'Punt' and 'Punt'
Omdat Python geen ingebouwde kennis heeft over het combineren van twee Punt-instanties, gooit het een exception. Operator overloading laat ons dat gedrag zelf definiëren.
Python Speciale Methodes
Methoden omringd door dubbele underscores – __init__, __str__, __add__, etc. – heten speciale methoden of "dunder" methoden. Ze worden impliciet aangeroepen door Python's runtime en zijn de hook-points voor operator overloading, container-protocollen en meer.
Bijvoorbeeld, de __str__-methode controleert hoe een object geconverteerd wordt naar een menselijk-leesbare string. Standaard toont printen van een object het geheugenadres, wat vaak niet nuttig is. __str__ overschrijven maakt debugging en logging veel duidelijker:
class Punt:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
Nu, wanneer we een Punt printen, krijgen we:
p1 = Punt(2, 3)
print(p1)
Uitvoer
(2, 3)
Deze representatie wordt ook gebruikt door str(p1) en format(p1) omdat Python intern p1.__str__() aanroept.
De +-operator overladen
Om optelling voor Punt-objecten aan te passen, implementeer __add__:
class Punt:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
def __add__(self, other):
return Punt(self.x + other.x, self.y + other.y)
Testen van het nieuwe gedrag:
p1 = Punt(1, 2)
p2 = Punt(2, 3)
print(p1 + p2)
Uitvoer
(3, 5)
Onder de motorkap voert Python p1.__add__(p2) uit, wat een verse Punt retourneert met de opgetelde coördinaten.
Hieronder een snel overzicht voor andere rekenkundige operatoren en de speciale methoden die je moet implementeren:
| Operator | Expressie | Speciale Methode |
|---|---|---|
| Optelling | p1 + p2 | __add__(self, other) |
| Aftrekking | p1 - p2 | __sub__(self, other) |
| Vermenigvuldiging | p1 * p2 | __mul__(self, other) |
| Macht | p1 ** p2 | __pow__(self, other) |
| Deling | p1 / p2 | __truediv__(self, other) |
| Gehele deling | p1 // p2 | __floordiv__(self, other) |
| Modulo | p1 % p2 | __mod__(self, other) |
| Linksshift | p1 << p2 | __lshift__(self, other) |
| Rechtsshift | p1 >> p2 | __rshift__(self, other) |
| Bitwise AND | p1 & p2 | __and__(self, other) |
| Bitwise OR | p1 | p2 | __or__(self, other) |
| Bitwise XOR | p1 ^ p2 | __xor__(self, other) |
| Bitwise NOT | ~p1 | __invert__(self) |
Vergelijkingsoperatoren overladen
Operator overloading is niet beperkt tot rekenkunde. Vergelijkingsoperatoren kunnen ook aangepast worden. Bijvoorbeeld, om punten te vergelijken op basis van hun afstand tot de oorsprong, overschrijf __lt__:
class Punt:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
def __lt__(self, other):
self_mag = self.x**2 + self.y**2
other_mag = other.x**2 + other.y**2
return self_mag < other_mag
Gebruik:
p1 = Punt(1, 1)
p2 = Punt(-2, -3)
p3 = Punt(1, -1)
print(p1 < p2) # True
print(p2 < p3) # False
print(p1 < p3) # False
Andere vergelijkingsmethodes volgen een vergelijkbaar patroon:
| Operator | Expressie | Speciale Methode |
|---|---|---|
| Kleiner dan | p1 < p2 | __lt__(self, other) |
| Kleiner dan of gelijk | p1 <= p2 | __le__(self, other) |
| Gelijk | p1 == p2 | __eq__(self, other) |
| Niet gelijk | p1 != p2 | __ne__(self, other) |
| Groter dan | p1 > p2 | __gt__(self, other) |
| Groter dan of gelijk | p1 >= p2 | __ge__(self, other) |
Door deze methoden zorgvuldig te definiëren, kun je custom objecten natuurlijk laten deelnemen in rekenkundige en vergelijkingscontexten, wat codeleesbaarheid en onderhoudbaarheid verbetert.
Python
- Python Datatypes onder de knie krijgen: Een praktische gids
- Python Operators onder de knie krijgen: Een uitgebreide gids
- Python Pass Statement onder de knie krijgen: Een praktische gids
- Python Functie-argumenten onder de knie krijgen: Positionele, Keyword en Default Parameters
- Python-dictionaries beheersen: aanmaken, manipuleren en geavanceerde technieken
- Python-erfelijkheid beheersen: concepten, syntax en praktische voorbeelden
- Python-iterators: hoe ze werken en hoe je je eigen maakt
- Python-closures uitgelegd: hoe geneste functies variabelen vangen
- Python's @property-decorator beheersen: schone, backward-compatibele getters & setters
- Python datetime beheersen: praktische gids voor datums, tijden en tijdzones
- Python's time.sleep() onder de knie krijgen: best practices, multithreading en real-world voorbeelden