Как локально переопределить __truediv__ для возврата дроби

В Python 3 деление целых чисел или чего-либо, включая число с плавающей запятой, приводит к числу с плавающей запятой:

>>> from fractions import Fraction
>>> f = Fraction(1, 2)
>>> f / 2
Fraction(1, 4)
>>> 2 / f
Fraction(4, 1)
>>> 1 / 2 
0.5
>>> 2 / 1 
2.0
>>> f / .1
5.0
>>> f / .2
2.5
>>> .2 / f
0.4

Я хотел бы, чтобы деление возвращало дроби, т. Е. Получало следующее поведение:

>>> 1 / 2
Fraction(1, 2)
>>> 2 / 1
Fraction(2, 1)

Я безуспешно пытался переопределить разделение:

>>> int.__truediv__ = lambda self, other: Fraction(self) / Fraction(other)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'int'

Каковы мои варианты? Я согласен представить класс MyFraction, производный от Fraction. По крайней мере, я хотел бы иметь возможность определить dict-подобный класс X таким образом, чтобы

>>> X({'a': 1/3}) == X({'a': Fraction(1, 3)})
True

N.B.: Кажется, изначально описанное мной поведение было задумано (см. PEP 238):

Если и когда в Python добавлен рациональный тип (см. PEP 239), истинное деление на целые и длинные числа, вероятно, должно возвращать рациональное число. Это позволяет избежать проблемы с истинным разделением целых и длинных значений с потерей информации. Но до тех пор, для согласованности, float — единственный выбор для истинного деления.


person equaeghe    schedule 14.06.2013    source источник
comment
Вы не можете. Вам придется создать подкласс int (что означает, что вы не сможете использовать целочисленные литералы). Сначала приведите свои операнды к Fraction объектам.   -  person Martijn Pieters    schedule 14.06.2013


Ответы (1)


Возможно, вам не следует этого делать, но вы можете исправить встроенные типы, используя Запретный плод.

person kindall    schedule 14.06.2013
comment
Это в некотором роде прекрасно, и в некотором роде ужасно. Никогда не слышал об этом модуле, но полезно знать... И согласен, не стоит этого делать. - person Matt Anderson; 14.06.2013