The fractions module provides exact rational number arithmetic. When you need to work with ratios, proportions, or avoid floating-point errors entirely, fractions are perfect.
Basic Usage
Create fractions from integers:
from fractions import Fraction
# From numerator and denominator
half = Fraction(1, 2)
print(half) # 1/2
# From integer
whole = Fraction(5)
print(whole) # 5
# Automatic reduction
reduced = Fraction(4, 8)
print(reduced) # 1/2From Strings
Parse fractions from strings:
from fractions import Fraction
# Fraction notation
f = Fraction('3/4')
print(f) # 3/4
# Decimal notation
f = Fraction('0.75')
print(f) # 3/4
# Scientific notation
f = Fraction('1.5e-2')
print(f) # 3/200From Floats (With Care)
Converting from floats preserves the exact binary representation:
from fractions import Fraction
# This might surprise you
f = Fraction(0.1)
print(f) # 3602879701896397/36028797018963968
# Use strings for exact values
f = Fraction('0.1')
print(f) # 1/10Arithmetic
All standard operations work:
from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(1, 4)
print(a + b) # 7/12
print(a - b) # 1/12
print(a * b) # 1/12
print(a / b) # 4/3
print(a ** 2) # 1/9No Precision Loss
Unlike floats, fractions are exact:
from fractions import Fraction
# Float version
f_sum = 0.1 + 0.1 + 0.1
print(f_sum == 0.3) # False
# Fraction version
frac_sum = Fraction('0.1') + Fraction('0.1') + Fraction('0.1')
print(frac_sum == Fraction('0.3')) # TrueAccessing Components
Get numerator and denominator:
from fractions import Fraction
f = Fraction(7, 12)
print(f.numerator) # 7
print(f.denominator) # 12Comparison
Comparisons work naturally:
from fractions import Fraction
a = Fraction(1, 3)
b = Fraction(2, 6)
c = Fraction(1, 2)
print(a == b) # True (auto-reduced)
print(a < c) # True
print(a > c) # FalseMixed Arithmetic
Fractions work with integers and floats:
from fractions import Fraction
f = Fraction(1, 2)
# With integers (stays Fraction)
print(f + 1) # 3/2
print(f * 3) # 3/2
# With floats (becomes float)
print(f + 0.5) # 1.0
print(type(f + 0.5)) # <class 'float'>Limiting Denominators
Approximate with a simpler fraction:
from fractions import Fraction
import math
# Pi as a fraction
pi_frac = Fraction(math.pi)
print(pi_frac) # Huge ugly fraction
# Limit denominator for simpler approximation
simple = pi_frac.limit_denominator(100)
print(simple) # 311/99
simpler = pi_frac.limit_denominator(10)
print(simpler) # 22/7 (classic approximation)Real-World Example: Recipe Scaling
from fractions import Fraction
def scale_recipe(ingredients, scale_factor):
"""Scale recipe ingredients exactly."""
scale = Fraction(scale_factor)
return {
name: amount * scale
for name, amount in ingredients.items()
}
recipe = {
'flour': Fraction('2 1/2'), # 2.5 cups
'sugar': Fraction('3/4'), # 3/4 cup
'butter': Fraction('1/3'), # 1/3 cup
}
# Scale to 1.5x
scaled = scale_recipe(recipe, '3/2')
for name, amount in scaled.items():
print(f"{name}: {amount}")
# flour: 15/4 (3.75 cups)
# sugar: 9/8 (1 1/8 cups)
# butter: 1/2Mixed Numbers
Parse and display mixed numbers:
from fractions import Fraction
# Parse mixed number (use space as separator)
mixed = Fraction('2') + Fraction('1/4')
print(mixed) # 9/4
# Display as mixed number
def to_mixed(f):
whole = int(f)
remainder = f - whole
if remainder:
return f"{whole} {remainder}" if whole else str(remainder)
return str(whole)
print(to_mixed(Fraction(9, 4))) # 2 1/4From Decimal
Convert Decimal to Fraction:
from fractions import Fraction
from decimal import Decimal
d = Decimal('0.125')
f = Fraction(d)
print(f) # 1/8GCD and LCM
Fractions use these internally, but you can compute them:
from math import gcd, lcm
# GCD
print(gcd(12, 18)) # 6
# LCM
print(lcm(4, 6)) # 12Probability Example
Calculate exact probabilities:
from fractions import Fraction
def dice_probability(successes, total_outcomes):
return Fraction(successes, total_outcomes)
# Rolling a 6 on one die
p_six = dice_probability(1, 6)
print(f"P(6) = {p_six}") # 1/6
# Rolling two 6s
p_two_sixes = p_six * p_six
print(f"P(two 6s) = {p_two_sixes}") # 1/36
# Complement: not rolling a 6
p_not_six = 1 - p_six
print(f"P(not 6) = {p_not_six}") # 5/6Performance
Fractions are slower than floats but faster than arbitrary-precision decimal for many operations:
from fractions import Fraction
from decimal import Decimal
# For exact arithmetic where performance isn't critical,
# fractions are often more natural than DecimalWhen to Use Fractions
Use fractions when:
- Working with ratios and proportions
- Exact arithmetic is required
- Results should remain as fractions (not decimals)
- Educational or mathematical contexts
Use Decimal when:
- Working with money (fixed decimal places)
- Need to control precision explicitly
Use float when:
- Performance matters
- Approximate values are acceptable
Fractions give you exact rational arithmetic. When you need to preserve mathematical relationships without rounding errors, they're the right choice.