You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Support .as_integer_ratio() in fractions.Fraction #82017
Currently, the fractions.Fraction constructor accepts an .as_integer_ratio() method only for the specific types "float" and "Decimal". It would be good to support this for arbitrary classes.
This is part of what was proposed in bpo-37822, but without adding the math.operator() function.
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = 1' 'Fraction(x, x)'
BEFORE: Mean +- std dev: 1.44 us +- 0.03 us
AFTER: Mean +- std dev: 1.46 us +- 0.02 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = Fraction(1)' 'Fraction(x)'
BEFORE: Mean +- std dev: 1.64 us +- 0.03 us
AFTER: Mean +- std dev: 1.30 us +- 0.04 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = Fraction(1)' 'Fraction(x, x)'
BEFORE: Mean +- std dev: 3.03 us +- 0.05 us
AFTER: Mean +- std dev: 2.34 us +- 0.06 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = 1.0' 'Fraction(x)'
BEFORE: Mean +- std dev: 1.82 us +- 0.02 us
AFTER: Mean +- std dev: 1.29 us +- 0.04 us
This proposition was rejected because it used as_integer_ratio() in both single- and two-argument forms of the Fraction constructor. But these two forms have different roles. The former converts a number to a Fraction or parses a string representation of fraction. The latter creates a fraction from two rationals (and this is perhaps too much, it could be limited to integers). Conversion from integer supports not only rational numbers, but also float and Decimal. Supporting as_integer_ratio() here would allow to convert float128 and other non-rational numbers to Fraction.
So I reopen this issue with more limited goal -- supporting as_integer_ratio() in a single-argument form of the Fraction constructor.
Agreed this would be a nice generalisation for the case of converting a user-defined type to a fraction (the user defined type just has to define as_integer_ratio and then Fraction(value) works as expected). But it should not apply to the 2-argument case.
Activity
jdemeyer commentedon Aug 13, 2019
Currently, the fractions.Fraction constructor accepts an .as_integer_ratio() method only for the specific types "float" and "Decimal". It would be good to support this for arbitrary classes.
This is part of what was proposed in bpo-37822, but without adding the math.operator() function.
serhiy-storchaka commentedon Aug 19, 2019
I afraid this can slow down the Fraction constructor.
serhiy-storchaka commentedon Aug 19, 2019
See bpo-37884 which uses a C accelerator.
jdemeyer commentedon Aug 19, 2019
Note that that doesn't replace this issue, because I need to support as_integer_ratio both in the *numerator* and *denominator*.
jdemeyer commentedon Aug 19, 2019
No, it doesn't! It even speeds up the constructor in some cases:
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = 1' 'Fraction(x)'
BEFORE: Mean +- std dev: 826 ns +- 20 ns
AFTER: Mean +- std dev: 814 ns +- 17 ns
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = 1' 'Fraction(x, x)'
BEFORE: Mean +- std dev: 1.44 us +- 0.03 us
AFTER: Mean +- std dev: 1.46 us +- 0.02 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = Fraction(1)' 'Fraction(x)'
BEFORE: Mean +- std dev: 1.64 us +- 0.03 us
AFTER: Mean +- std dev: 1.30 us +- 0.04 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = Fraction(1)' 'Fraction(x, x)'
BEFORE: Mean +- std dev: 3.03 us +- 0.05 us
AFTER: Mean +- std dev: 2.34 us +- 0.06 us
./python -m perf timeit --duplicate 200 -s 'from fractions import Fraction; x = 1.0' 'Fraction(x)'
BEFORE: Mean +- std dev: 1.82 us +- 0.02 us
AFTER: Mean +- std dev: 1.29 us +- 0.04 us
rhettinger commentedon Jan 2, 2022
I don't think this is a door we should open:
This currently raises a useful exception:
TypeError: both arguments should be Rational instances
That is especially helpful in avoiding cases like this:
>>> Fraction(1.1, 3.3) Fraction(2476979795053773, 7430939385161318)If that output is desired, the two conversions should be explicit.
>>> Fraction(1.1) / Fraction(3.3) Fraction(2476979795053773, 7430939385161318I recommend rejecting this feature request as being more likely to be hazardous than helpful.
serhiy-storchaka commentedon Apr 21, 2022
Concur with @rhettinger.
serhiy-storchaka commentedon Jun 8, 2024
This proposition was rejected because it used
as_integer_ratio()in both single- and two-argument forms of the Fraction constructor. But these two forms have different roles. The former converts a number to a Fraction or parses a string representation of fraction. The latter creates a fraction from two rationals (and this is perhaps too much, it could be limited to integers). Conversion from integer supports not only rational numbers, but alsofloatandDecimal. Supportingas_integer_ratio()here would allow to convertfloat128and other non-rational numbers to Fraction.So I reopen this issue with more limited goal -- supporting
as_integer_ratio()in a single-argument form of the Fraction constructor.pythongh-82017: Support as_integer_ratio() in the Fraction constructor
pfmoore commentedon Jun 8, 2024
Agreed this would be a nice generalisation for the case of converting a user-defined type to a fraction (the user defined type just has to define
as_integer_ratioand thenFraction(value)works as expected). But it should not apply to the 2-argument case.gh-82017: Support as_integer_ratio() in the Fraction constructor (GH-…