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
[muokkaa | muokkaa wikitekstiä]Tä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
[muokkaa | muokkaa wikitekstiä]Alla 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 | muokkaa wikitekstiä]- 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: |