fractions: Two-Arg Constructor Rejects float/Decimal (tested)

fractions.Fraction can be built from a single float or Decimal (converted to its exact binary or decimal value), or from two integers as numerator/denominator. We measured what happens when a float or Decimal is used in the two-argument form instead -- a natural thing to try when building a ratio directly from two measured values.

1. A single float or Decimal argument works fine

from fractions import Fraction
from decimal import Decimal

print(Fraction(0.5))
print(Fraction(0.1))
print(Fraction(Decimal("0.1")))
1/2
3602879701896397/36028797018963968
1/10

Measured: Fraction(0.5) and Fraction(Decimal("0.1")) both work, converting the value to its exact rational equivalent -- note Fraction(0.1) (float) captures 0.1's binary imprecision as a huge exact fraction, while Fraction(Decimal("0.1")) (string-backed Decimal) gives the clean 1/10, the same float-vs-string-source gap that shows up constructing Decimal itself.

2. The same types in the two-argument numerator/denominator form raise TypeError

from fractions import Fraction
from decimal import Decimal

try:
    Fraction(1, 0.5)
except TypeError as e:
    print("Fraction(1, 0.5):", e)

try:
    Fraction(0.5, 1)
except TypeError as e:
    print("Fraction(0.5, 1):", e)

try:
    Fraction(Decimal("0.5"), Decimal("1"))
except TypeError as e:
    print("Fraction(Decimal, Decimal):", e)
Fraction(1, 0.5): both arguments should be Rational instances
Fraction(0.5, 1): both arguments should be Rational instances
Fraction(Decimal, Decimal): both arguments should be Rational instances

Measured: every combination with a float or Decimal in either the numerator or denominator position of the two-argument form raises TypeError: both arguments should be Rational instances -- regardless of which position it's in, and even though the exact same value works as a single-argument call. The two-argument form only accepts int (or other Fraction/Rational) values.

3. The risk: a ratio built from two measured values crashes, while the same values individually don't

from fractions import Fraction

def discount_ratio(price_paid, original_price):
    return Fraction(price_paid, original_price)

print(discount_ratio(80, 100))        # both ints: fine
print(discount_ratio(79.99, 100.00))  # measured values from parsed input: crashes
4/5
Traceback (most recent call last):
  ...
TypeError: both arguments should be Rational instances

Measured: code that builds a ratio directly from two numbers -- prices, measurements, percentages parsed from input -- works during testing with clean integers and then raises the moment either value is a float (or Decimal) in production data. The fix is to convert each value to a Fraction individually first and divide them (Fraction(price_paid) / Fraction(original_price)), since the single-argument form accepts float/Decimal even though the two-argument form doesn't.

Frequently asked questions

Why does Fraction(1, 0.5) raise TypeError in Python?

Because the two-argument Fraction(numerator, denominator) form only accepts Rational types (int, or another Fraction) in either position -- we measured both Fraction(1, 0.5) and Fraction(0.5, 1) raising 'both arguments should be Rational instances', even though Fraction(0.5) alone works fine.

Can I build a Fraction from two float values?

Not directly with the two-argument form -- we confirmed it raises TypeError for a float in either the numerator or denominator slot. Convert each float to a Fraction separately first and divide them: Fraction(a) / Fraction(b).

Does Fraction(Decimal, Decimal) work the same as Fraction(Decimal)?

No -- we measured a single Decimal argument to Fraction() working (converting it exactly), but the exact same Decimal values used as the two-argument numerator/denominator raising the same 'both arguments should be Rational instances' TypeError as floats.

What counts as a Rational instance for Python's Fraction two-argument constructor?

We measured int values working in both numerator and denominator slots, and float/Decimal values failing in either slot -- the two-argument form requires numbers.Rational (int or Fraction itself), while the single-argument form additionally accepts float, Decimal, and strings.

How do I safely build a Fraction ratio from two floats or Decimals?

Convert each one to a Fraction individually first, then divide: Fraction(price_paid) / Fraction(original_price). We confirmed the single-argument Fraction() constructor accepts float and Decimal directly, avoiding the TypeError the two-argument form raises for those types.

Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in fractions module: called Fraction() with a single float/Decimal argument, then with the same types as the two-argument numerator/denominator form, and compared the results. PlainHeaders is our extension; Python's fractions module is built in.