Подкласс типа float в Python, не может перехватить исключение в __init __ () - PullRequest
9 голосов
/ 20 декабря 2009

В Python 2.5 мне нужно использовать числа с плавающей точкой с измененным методом __str__(). Также мне нужно знать, когда конструктор выходит из строя.

Почему я не могу поймать исключения из float.__init__()?

Как лучше всего обратиться к числовому значению моего производного объекта с плавающей точкой? В моем коде я использую float(self).

class My_Number(float):
    def __init__(self, float_string):
        try:
            super(My_Number, self).__init__(float_string)
        except (TypeError, ValueError):
            raise My_Error(float_string)

    def __str__(self):
        if int(float(self)) == float(self):
            return str(int(float(self)))
        else:
            return str(round(float(self), 2))


>>> n = My_Number('0.54353')
>>> print n
0.54

>>> n = My_Number('5.0')
>>> print n
5

>>> n = My_Number('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: invalid literal for float(): foo

Ответы [ 2 ]

18 голосов
/ 20 декабря 2009

float является неизменным, поэтому его __init__, инициализатор , в основном не работает - ничего существенного там не может произойти, потому что объект self нельзя изменить (если он на самом деле это экземпляр float, а не подкласса - но, конечно, __init__ должен * *1008* работать с этим предположением; -).

Следовательно, все действие происходит в __new__, собственном конструкторе , как и для других неизменяемых типов, таких как int, str, tuple и т. Д. Распространенной ошибкой считается, что __init__ является конструктором: это не так, он принимает уже построенный объект в качестве первого аргумента self и «инициализирует» его (если это возможно, т. Е. Если это self изменяемый! -) - сама конструкция происходит в __new__.

Итак, ваш float подкласс должен запуститься:

class My_Number(float):
  def __new__(cls, float_string):
    try: return float.__new__(cls, float_string)
    except (TypeError, ValueError): raise My_Error(float_string)

и вы можете удалить __init__, который не нужен. Сейчас:

>>> n = My_Number('foo')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 4, in __new__
NameError: global name 'My_Error' is not defined

(конечно, было бы еще лучше, если бы у был определен класс исключений My_Error; -).

7 голосов
/ 20 декабря 2009

вместо __new__:

class F(float):
    def __new__(cls, *arg, **kw):
        try:
            return float.__new__(cls, *arg, **kw)
        except ValueError:
            raise Exception("foo")

print F("3.5")            
print F("asdf")

Также «я» - это уже число с плавающей точкой, поэтому не нужно говорить «плавать» («я»), просто «я» подойдет:

def __str__(self):
    return "%.2f" % self
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...