Mailing List Archive

Problem with __sub__
The class Betragswert is used for numerical values as string or integer
and for additions and subtraction.

If on the left side is '0' the result of a subtraction is wrong.

*    b1 = Betragswert(500)
    b2 = 0 + b1
    b3 = 0 - b1
    b4 = 5 + b1
    b5 = 5 - b1*

print(b1, b2, b3, b4, b5) shows 5,00 5,00 5,00 5,05 4,95; the third
value (b3) should be -5,00 (not 5,00).

Why is the substraction wrong?

This is the module:

import locale

locale.setlocale(locale.LC_ALL, "")
Trennzeichen = locale.localeconv()["thousands_sep"]

def bereinigen(t):
        lg = len(t)
        if lg > 0:
            if t[lg-1] == '\n':
                return t[0:lg-1]
        return t


class Betragswert:
    def __init__(self, Wert):
        self._Betrag = 0
        if isinstance(Wert, type("123")):
            "Zeichenkette wurde übergeben"
            self._Betrag = _zeichenketteNACHganzzahl(Wert)
            return
        if isinstance(Wert, type(23)):
            "Cents wurden übergeben"
            self._Betrag = int(Wert)
            return
        if isinstance(Wert, type(self)):
            "Instanz der Klasse Betragswert wurde übergeben"
            self._Betrag = Wert.copy()
            return
        raise TypeError("Umsetzung als Betragswert nicht möglich: " +
repr(Wert))

    def __str__(self):
        e, c = divmod(abs(self._Betrag), 100)
        cents = repr(c)
        cents = "0" * (2 - len(cents)) + cents
        return (
            "-"[: self._Betrag < 0]
            + locale.format_string("%d", e, grouping=1)
            + locale.localeconv()["decimal_point"]
            + cents
        )

    def __repr__(self):
        return "Betragswert " + repr((str(self)))

    def copy(self):
        return self._Betrag

    def __cmp__(self, anderer):
        return cmp(self._Betrag, Betragswert(anderer)._Betrag)

    def __neg__(self):
        return Betragswert(-self._Betrag)

    def __abs__(self):
        if self._Betrag >= 0:
            return self.copy()
        else:
            return -self._Betrag

    def __add__(self, zweiter):
        if not isinstance(zweiter, type(self)):
            zweiter = Betragswert(zweiter)
        return Betragswert(self._Betrag + zweiter._Betrag)

    def __radd__(self, zweiter):
        if not isinstance(zweiter, type(self)):
            zweiter = Betragswert(zweiter)
        return Betragswert(self._Betrag + zweiter._Betrag)


    def __sub__(self, zweiter):
        if not isinstance(zweiter, type(self)):
            zweiter = Betragswert(zweiter)
        return Betragswert(self._Betrag - zweiter._Betrag)

    def __rsub__(self, zweiter):
        if not isinstance(zweiter, type(self)):
            zweiter = Betragswert(zweiter)
        return Betragswert(self._Betrag - zweiter._Betrag)

    def hol(self): # notwendig für Tests
        return self._Betrag

Reg_Ausdruck = (
    r"""
    \s*
    (?P<vorzeichen>[-+])?
    (
        (?P<vor>\d+) ("""
    + "\\"
    + locale.localeconv()["decimal_point"]
    + r"""
                        (?P<nach>\d*))?
    |
        """
    + "\\"
    + locale.localeconv()["decimal_point"]
    + r"""
                         (?P<nurnach>\d+)
    )
    \s* $
"""
)
import re

_parser = re.compile(Reg_Ausdruck, re.VERBOSE).match

del re


def _zeichenketteNACHganzzahl(s):
    s = bereinigen(s)
    """s --> L"""
    s = s.replace(Trennzeichen, "")
    m = _parser(s)
    if m is None:
        raise ValueError("Dies ist keine Zahl: " + repr(s))

    vor = m.group("vor")
    if vor is None:
        vor = "0"
        nach = m.group("nurnach")
    else:
        nach = m.group("nach")
        if nach is None or nach == "":
            nach = "0"
    if len(nach) == 1:
        nach = nach + "0"
    elif len(nach) > 2:
        nach = nach[0:2]
    b1 = Betragswert(500)
    b2 = 0 + b1
    b3 = 0 - b1
    b4 = 5 + b1
    b5 = 5 - b1
    z = int(vor) * 100 + int(nach)

    if m.group("vorzeichen") == "-":
        z = -z
    return z


if __name__ == '__main__':
    b1 = Betragswert(500)
    b2 = 0 + b1
    b3 = 0 - b1
    b4 = 5 + b1
    b5 = 5 - b1
    print(b1, b2, b3, b4, b5)




--
https://mail.python.org/mailman/listinfo/python-list
RE: Problem with __sub__ [ In reply to ]
I believe your problem is __rsub__, not __sub__.
When you have <something else> <operator> <something of this class> then that uses the "r" version of the operators.

In your __rsub__ (used when you have <other> - <this>) you instead return <this> - <other> which is backwards.

Notice how the final return should also be -4,95 and not the +4,95 it's returning.

> If on the left side is '0' the result of a subtraction is wrong.
>
> * b1 = Betragswert(500)
> b2 = 0 + b1
> b3 = 0 - b1
> b4 = 5 + b1
> b5 = 5 - b1*
>
> print(b1, b2, b3, b4, b5) shows 5,00 5,00 5,00 5,05 4,95; the third
> value (b3) should be -5,00 (not 5,00).
>
> Why is the substraction wrong?
> def __rsub__(self, zweiter):
> if not isinstance(zweiter, type(self)):
> zweiter = Betragswert(zweiter)
> return Betragswert(self._Betrag - zweiter._Betrag)
--
https://mail.python.org/mailman/listinfo/python-list