Seite 1 von 1
TypeError bei zwei gleichen types
Verfasst: Dienstag 17. Mai 2022, 21:31
von mm96
Hallo zusammen,
ich les grad ein Beispiel über Klassen (s.u.).
Der Code erzeugt bei mir folgenden Error:
TypeError: unsupported operand type(s) for /: 'IntervalMath' and 'IntervalMath'
Ich kapier nicht, warum die Divison nicht funktioniert, die anderen Operationen aber anstandslos durchlaufen...
Code: Alles auswählen
class IntervalMath:
def __init__(self, lower, upper):
self.lo = float(lower)
self.up = float(upper)
def __add__(self, other):
a, b, c, d = self.lo, self.up, other.lo, other.up
return IntervalMath(a + c, b + d)
def __sub__(self, other):
a, b, c, d = self.lo, self.up, other.lo, other.up
return IntervalMath(a - d, b - c)
def __mul__(self, other):
a, b, c, d = self.lo, self.up, other.lo, other.up
return IntervalMath(min(a*c, a*d, b*c, b*d), max(a*c, a*d, b*c, b*d))
def __div__(self, other):
a, b, c, d = self.lo, self.up, other.lo, other.up
# [c, d] cannot contain zero:
if c*d <= 0:
raise ValueError\
(f'Interval {other} cannot be denominator because it contains zero')
return IntervalMath(min(a/c, a/d, b/c, b/d), max(a/c, a/d, b/c, b/d))
def __str__(self):
return f'[{self.lo:g}, {self.up:g}]'
if __name__ == '__main__':
I = IntervalMath
a = I(-3, -2)
b = I(4, 5)
expr = 'a+b', 'a-b', 'a*b', 'a/b'
for e in expr:
print(f'{e} =', eval(e))
Viele Grüße
Re: TypeError bei zwei gleichen types
Verfasst: Dienstag 17. Mai 2022, 21:35
von sparrow
Es gibt keine magische Funktion, die __div__ heißt. Keine Ahnung, ob es die in Python 2 mal gab. Heute gibt es __truediv__ für / und __floordiv__ für //.
Re: TypeError bei zwei gleichen types
Verfasst: Dienstag 17. Mai 2022, 22:09
von __blackjack__
@mm96: Man sollte keine kryptischen Abkürzungen verwenden. `lo` und `up` sollten wie die Argumente von der `__init__()` heissen.
Der Test mit ``c * d <= 0`` testet nicht das was die Ausnahmemeldung sagt. Wenn das wahr ist, bedeutet das nicht, das entweder `c` oder `d` 0 ist. Das kann auch einfach nur bedeuten das einer der Werte negativ ist. Und auf 0 braucht man auch gar nicht extra testen, denn das würde ja sowieso einen `ZeroDivisionError` auslösen. Das kann man dann auch einfach nutzen ohne einen extra Test und eine andere Ausnahme auszulösen.
`eval()` sollte man vermeiden wo es geht und es geht eigentlich fast überall.
Code: Alles auswählen
#!/usr/bin/env python3
from operator import add, mul, sub, truediv
class IntervalMath:
def __init__(self, lower, upper):
self.lower = float(lower)
self.upper = float(upper)
def __repr__(self):
return f"{self.__class__.__name__}({self.lower!r}, {self.upper!r})"
def __str__(self):
return f'[{self.lower:g}, {self.upper:g}]'
def __add__(self, other):
return IntervalMath(self.lower + other.lower, self.upper + other.upper)
def __sub__(self, other):
return IntervalMath(self.lower - other.lower, self.upper - other.upper)
def __mul__(self, other):
values = [
self.lower * other.lower,
self.lower * other.upper,
self.upper * other.lower,
self.upper * other.upper,
]
return IntervalMath(min(values), max(values))
def __truediv__(self, other):
values = [
self.lower / other.lower,
self.lower / other.upper,
self.upper / other.lower,
self.upper / other.upper,
]
return IntervalMath(min(values), max(values))
def main():
a = IntervalMath(-3, -2)
b = IntervalMath(4, 5)
for symbol, function in [
("+", add),
("-", sub),
("*", mul),
("/", truediv),
]:
print(f"a{symbol}b = {function(a, b)}")
if __name__ == '__main__':
main()
Re: TypeError bei zwei gleichen types
Verfasst: Mittwoch 18. Mai 2022, 06:16
von mm96
Alles klar, vielen Dank!
Auch für die Umgehung des eval, werd ich mir merken.
Bei dem Teilen durch Null wollte man glaub testen, ob Null im Intervall liegt, ich hab mir aber die Intervallarithmetik dafür nicht genug angeschaut: Es soll wohl nur [a, b]/[c, d] vermieden werden, wenn 0 Element von [c, d] ist.
Danke nochmal!
Re: TypeError bei zwei gleichen types
Verfasst: Mittwoch 18. Mai 2022, 07:49
von Sirius3
@mm96: die Bedingung `c*d <= 0` ist schon korrekt, einfache zu verstehen wäre wohl `c <= 0 and d >= 0`.
Re: TypeError bei zwei gleichen types
Verfasst: Mittwoch 18. Mai 2022, 10:26
von __blackjack__
Ah, okay, dann würde ich den Intervalltyp wahrscheinlich um ein `__contains__` erweitern und den Test als ``0 in other`` ausdrücken. Oder zumindest `c` und `d` ”aussschreiben” und die Vergleichoperatoren verketten: ``other.lower <= 0 <= other.upper``.
Mit `__contains__()` und ``in``:
Code: Alles auswählen
#!/usr/bin/env python3
from operator import add, mul, sub, truediv
class IntervalMath:
def __init__(self, lower, upper):
self.lower = float(lower)
self.upper = float(upper)
def __repr__(self):
return f"{self.__class__.__name__}({self.lower!r}, {self.upper!r})"
def __str__(self):
return f'[{self.lower:g}, {self.upper:g}]'
def __contains__(self, value):
return self.lower <= value <= self.upper
def __add__(self, other):
return IntervalMath(self.lower + other.lower, self.upper + other.upper)
def __sub__(self, other):
return IntervalMath(self.lower - other.lower, self.upper - other.upper)
def __mul__(self, other):
values = [
self.lower * other.lower,
self.lower * other.upper,
self.upper * other.lower,
self.upper * other.upper,
]
return IntervalMath(min(values), max(values))
def __truediv__(self, other):
if 0 in other:
raise ValueError(f"denominator {other!r} contains 0")
values = [
self.lower / other.lower,
self.lower / other.upper,
self.upper / other.lower,
self.upper / other.upper,
]
return IntervalMath(min(values), max(values))
def main():
a, b = IntervalMath(-3, -2), IntervalMath(4, 5)
for symbol, function in [
("+", add),
("-", sub),
("*", mul),
("/", truediv),
]:
print(f"a{symbol}b = {function(a, b)}")
if __name__ == "__main__":
main()
Re: TypeError bei zwei gleichen types
Verfasst: Mittwoch 18. Mai 2022, 23:28
von mm96
Ah, das sieht auch gut aus, übernehm ich.
Eine Frage hätt ich noch zu Deiner Funktion __repr__:
Warum benutzt Du "{self.lower!r}" mit !r; ist es wichtig, dass der Wert hier als string übergeben wird?
Re: TypeError bei zwei gleichen types
Verfasst: Donnerstag 19. Mai 2022, 12:04
von __blackjack__
@mm96: Das "!r" sorgt dafür das auch bei diesem Wert die `repr()`- und nicht die `str()`-Repräsentation verwendet wird. Die können ja unterschiedlich sein und nur die `repr()`-Darstellung ”garantiert” wie das Ergebnis aussieht, also das es entweder als Python-Code darsgestellt wird, der wieder zum gleichen Wert führen würde, oder in “spitze Klammern“ eingefasst wenigstens genug Informationen zur Fehlersuche dargestellt werden. Ist theoretisch hier überflüssig weil man relativ sicher sein kann, dass es sich um Werte vom Typ `float` handelt. Andererseits wäre genau das ein Kritikpunkt, denn eigentlich sollte man diese Klasse auch mit `int` oder `Decimal` oder was auch immer sich wie eine Zahl verhält, verwendet werden können und die `__init__()` da nix umwandeln, denn da gehen dann eventuell Informationen verloren. Zum Beispiel wenn es mit `Decimal`-Objekten aufgerufen wird.
Re: TypeError bei zwei gleichen types
Verfasst: Freitag 20. Mai 2022, 07:26
von mm96
Ich glaub ich komm langsam drauf.
Wenn man also z. B. ne Formel in der __str__ ausgeben würde, wäre die Benutzung von repr() sinnvoller wenn das Ganze in der __repr__-Methode stattfindet, um auch noch Infos über das Objekt oder den Code zu bekommen.
Hab mal noch das Decimal-Modul angeschaut, wahrscheinlich würde es mehr Sinn machen, alles in Decimals statt in floats zu rechnen, je nach Genauigkeitsanspruch.
Danke für die Hinweise!
Re: TypeError bei zwei gleichen types
Verfasst: Freitag 20. Mai 2022, 10:21
von Kebap
> wahrscheinlich würde es mehr Sinn machen, alles in Decimals statt in floats zu rechnen
Blackjack meint, dass du einfach mit dem (Typ) rechnen solltest, was an die Klasse übergeben wird, und nicht in __init__ den Typ verändern sollst.