Python 3/Operaattoreiden kuormittaminen
Operaattoreiden kuormittaminen tarkoittaa operandien väliin tai eteen laitettavien operaattoreiden, kuten +, -, *, /, toteuttamista omille luokille. Olemme jo nähneet miten operaattoria + voi käyttää paitsi numeroiden yhteenlaskuun myös yhdistämään kaksi listaa tai merkkijonoa ja operaattoreita * ja ** voi käyttää paitsi kertolaskuun ja potensiin korottamiseen myös monikon ja sanakirjan hajottamiseen funktion argumenteiksi.
Operaattori kuormitetaan toteuttamalla omassa oliossa erityinen metodi.
operaattori | metodi |
---|---|
+ | __add__(self, other) |
– | __sub__(self, other) |
* | __mul__(self, other) |
/ | __truediv__(self, other) |
// | __floordiv__(self, other) |
% | __mod__(self, other) |
** | __pow__(self, other) |
@ | __matmul__(self, other) |
>> | __rshift__(self, other) |
<< | __lshift__(self, other) |
& | __and__(self, other) |
| | __or__(self, other) |
^ | __xor__(self, other) |
< | __lt__(self, other) |
> | __gt__(self, other) |
<= | __le__(self, other) |
>= | __ge__(self, other) |
== | __eq__(self, other) |
!= | __ne__(self, other) |
– | __neg__(self) |
+ | __pos__(self) |
~ | __invert__(self) |
in | __contains__(self, key) |
operaattori | metodi |
---|---|
+= | __iadd__(self, other) |
-= | __isub__(self, other) |
*= | __imul__(self, other) |
/= | __itruediv__(self, other) |
//= | __ifloordiv__(self, other) |
%= | __imod__(self, other) |
**= | __ipow__(self, other) |
>>= | __irshift__(self, other) |
<<= | __ilshift__(self, other) |
&= | __iand__(self, other) |
= | __ior__(self, other) |
^= | __ixor__(self, other) |
Binaarisista operaattoresta on olemassa myös käänteinen versio, jossa nimen eteen tulee r.
Loogisia operaattoreita and, or ja not ei voi kuormittaa.
Esimerkki vertailuoperaattoreiden kuormittamisesta
muokkaaTässä teemme tyypin kps, jolla voi esittää kivi–paperi–sakset-leikin arvoja ja vertailla niitä keskenään.
class kps:
def __init__(self, val):
self.val = val
def __eq__(self, other):
return (self.val == other.val)
def __gt__(self, other):
if self.val == "paperi" and other.val == "kivi":
return True
if self.val == "sakset" and other.val == "paperi":
return True
if self.val == "kivi" and other.val == "sakset":
return True
return False
def __ge__(self, other):
return self.__eq__(other) or self.__gt__(other)
def __lt__(self, other):
if self.val == "kivi" and other.val == "paperi":
return True
if self.val == "paperi" and other.val == "sakset":
return True
if self.val == "sakset" and other.val == "kivi":
return True
return False
def __le__(self, other):
return self.__eq__(other) or self.__lt__(other)
def __repr__(self):
return f'{self.val}'
kivi = kps("kivi")
paperi = kps("paperi")
sakset = kps("sakset")
if __name__ == "__main__":
from itertools import combinations_with_replacement
units = [kivi, paperi, sakset]
pairs = [x for x in combinations_with_replacement(units, 2)]
print("==")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, "==", b)
print(a == b)
print()
print("!=")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, "!=", b)
print(a != b)
print()
print(">")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, ">", b)
print(a > b)
print()
print("<")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, "<", b)
print(a < b)
print()
print(">=")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, ">=", b)
print(a >= b)
print()
print("<=")
for pair in pairs:
a = pair[0]
b = pair[1]
print(a, "<=", b)
print(a <= b)
print()
Tulostaa
== kivi == kivi True kivi == paperi False kivi == sakset False paperi == paperi True paperi == sakset False sakset == sakset True != kivi != kivi False kivi != paperi True kivi != sakset True paperi != paperi False paperi != sakset True sakset != sakset False > kivi > kivi False kivi > paperi False kivi > sakset True paperi > paperi False paperi > sakset False sakset > sakset False < kivi < kivi False kivi < paperi True kivi < sakset False paperi < paperi False paperi < sakset True sakset < sakset False >= kivi >= kivi True kivi >= paperi False kivi >= sakset True paperi >= paperi True paperi >= sakset False sakset >= sakset True <= kivi <= kivi True kivi <= paperi True kivi <= sakset False paperi <= paperi True paperi <= sakset True sakset <= sakset True
Esimerkki bittioperaatoiden kuormittamisesta
muokkaaAlla olevassa esimerkissä teemme kolmiarvoista totuusarvoa esittävän luokan, jossa tosi- ja epätosi-arvojen lisäksi on epätietoisuutta esittävä arvo (?). Koska and-, or- ja not-operaattoreita ei voi kuormittaa käytämme niiden sijasta &-, |- ja ~-operaattoreita. Metodia __repr__ käsiteltiin osassa Luokka.
class tri:
def __init__(self, val):
self.__val = val
@property
def val(self):
return self.__val
def __and__(self, other):
if self.val == "0" or other.val == "0":
return tri("0")
if self.val == "?" or other.val == "?":
return tri("?")
else:
return tri("1")
def __or__(self, other):
if self.val == "1" or other.val == "1":
return tri("1")
elif self.val == "?" or other.val == "?":
return tri("?")
else:
return tri("0")
def __invert__(self):
if self.val == "?":
return tri("?")
elif self.val == "1":
return tri("0")
else:
return tri("1")
def __repr__(self):
return f"tri('{self.__val}')"
if __name__ == "__main__":
from itertools import combinations_with_replacement
values = [tri("0"), tri("?"), tri("1")]
pairs = [x for x in combinations_with_replacement(values, 2)]
print(f"{'NOT': ^21}")
for a in values:
print("~", a, "=", ~a)
print()
print(f"{'AND': ^30}")
for a, b in pairs:
print(a, "&", b, "=", a & b)
print()
print(f"{'OR': ^30}")
for a, b in pairs:
print(a, "|", b, "=", a | b)
Tulostaa
NOT ~ tri('0') = tri('1') ~ tri('?') = tri('?') ~ tri('1') = tri('0') AND tri('0') & tri('0') = tri('0') tri('0') & tri('?') = tri('0') tri('0') & tri('1') = tri('0') tri('?') & tri('?') = tri('?') tri('?') & tri('1') = tri('?') tri('1') & tri('1') = tri('1') OR tri('0') | tri('0') = tri('0') tri('0') | tri('?') = tri('?') tri('0') | tri('1') = tri('1') tri('?') | tri('?') = tri('?') tri('?') | tri('1') = tri('1') tri('1') | tri('1') = tri('1')
Harjoitukset
muokkaa- Tee murtolukua esittävä luokka ja toteuta sille ainakin operaattorit +, -, * ja /. Voit käyttä sieventämisessä apuna math-moduulin gcd-funktiota, joka palauttaa kahden annetun luvun suurimman yhteisen tekijän. Murtoluvuilla laskemista on käsitelty Matematiikan kirjassa.
Johdanto: | |
---|---|
Tietotyypit ja tietorakenteet: |
Luvut - Merkkijonot - Lista - Monikko (tuple) - Sanakirja - Joukko (set) |
Ohjausrakenteet | |
Muut kielen rakenteet: |
Moduuli - Luokka - Funktio - Virheidenhallinta - Tiedosto |
Graafinen käyttöliittymä: | |
Harjoitustehtäviä: | |
Lisätiedot ja lähteet: |