подкласс float для изменения поведения и поведения __str__ - PullRequest
3 голосов
/ 23 февраля 2020

Я использовал подкласс float, чтобы изменить его метод __str__(), чтобы он заканчивался символом (в моем случае €).

Ввод фильтруется для удаления символа (в моем случае €).

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} €'

Но при печати возникает ошибка рекурсивной печати. ​​

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

Ошибка:

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

 [Previous line repeated 329 more times]

RecursionError: maximum recursion depth exceeded

Ответы [ 4 ]

3 голосов
/ 23 февраля 2020

Используйте super() для вызова метода родителя и избежания ошибки рекурсии.

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


>>> g = Euro('123.23 €')
>>> print(g)
123.23 €
2 голосов
/ 23 февраля 2020

Не используйте наследование; Euro не является разновидностью float, и деньги никогда не должны представляться с использованием float s из-за неточности приближений с плавающей точкой действительных чисел.

Вместо этого используйте состав для хранения атрибута, представляющего количество евро, используя что-то вроде decimal.Decimal для представления евро и центов точно .

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} €'
0 голосов
/ 25 февраля 2020

Я получил следующий код:

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} €'

Я не вижу необходимости в подклассе. Я добавил поддержку операторов +/-, которые возвращают еврообъект.

Результат:

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

print (h+g) # --> 11.00 €
print (h-g) # -->  9.00 €
0 голосов
/ 23 февраля 2020

Рассмотрим код,

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

Теперь, когда вы вызываете print(g), на самом деле происходит то, что print(g) вызывает __str__ метод Euro, который возвращает f'{self} €', как self относится к самому экземпляру Euro, это вызывает дальнейшие вызовы __str__ метода Euro, и эта рекурсия продолжается до тех пор, пока stackoverflow не произойдет.

Для решения этой проблемы проблема, вы должны убедиться, что рекурсия не произойдет, вы можете добиться этого следующим образом:

class Euro(float):
    def __new__(self, value):
        self.value =  "".join([_ for  _ in value if _ != '€' and _ != " " ])
        return float.__new__(self, self.value)

    def __str__(self):
        return f'{self.value} €' # or return super().__str__() + ' €'

Теперь, когда вы звоните, print(g) это вернет, 123.23 € как и ожидалось.

Надеюсь, это поможет!

...