float sub-class to alter intake and __str__ behaviour

Viewed 61

I've sub-classed float to alter its __str__() method to end with a symbol (in my case €).

The input is filtered to remove a symbol (in my case €).

class Euro(float):
    def __new__(cls, value):
        v = ''.join([_ for  _ in value if _ != '€' ])
        return super(Euro, cls).__new__(cls, v)

    def __str__(self):
        return f'{self} €'

But when I print, I get a recursive print error.

g = Euro('123.23 €')
print (g) 

Error:

Euro.py, line  __str__
    return f'{self} €'

 [Previous line repeated 329 more times]

RecursionError: maximum recursion depth exceeded
3 Answers

Use super() to call the parent's method and avoid the recursion error.

def __str__(self):
    return super().__str__() + ' €'


>>> g = Euro('123.23 €')
>>> print(g)
123.23 €

Don't use inheritance; a Euro is not a kind of float, and money should never be represented using floats due to the imprecision of the floating-point approximations of real numbers.

Instead, use composition to store an attribute representing the number of Euros, using something like decimal.Decimal to represent the euros-and-cents exactly.

from decimal import Decimal


class Euro:
    # In accordance with how to use super properly,
    # always accept and pass on unrecognized keyword arguments.
    def __init__(self, value, **kwargs):
        super().__init__(**kwargs)

        self.value = Decimal(value.strip('€'))

    def __str__(self):
        return f'{self.value} €'

I've ended up with the following code :

from decimal import Decimal

class Euro:
    def __init__(self, value):
        if isinstance(value, str):
            value = value.strip(' €')
        self.value = Decimal(value)

    def __add__(self, other):
        return Euro(self.value + other.value)

    def __sub__(self,other):
        return Euro(self.value - other.value)

    def __str__(self):
        return f'{self.value} €'

I do not see the need to sub-class. I've added support for +/- operators that return a Euro-object.

The result is :

g = Euro(1.00)
h = Euro('10.00 €')

print (h+g) # --> 11.00 €
print (h-g) # -->  9.00 €
Related