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/2

From 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/200

From 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/10

Arithmetic

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/9

No 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'))  # True

Accessing Components

Get numerator and denominator:

from fractions import Fraction
 
f = Fraction(7, 12)
 
print(f.numerator)    # 7
print(f.denominator)  # 12

Comparison

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)   # False

Mixed 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/2

Mixed 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/4

From Decimal

Convert Decimal to Fraction:

from fractions import Fraction
from decimal import Decimal
 
d = Decimal('0.125')
f = Fraction(d)
print(f)  # 1/8

GCD 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))    # 12

Probability 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/6

Performance

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 Decimal

When 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.

React to this post: