Skip to main content

Fraction

A modern, lightweight, immutable, and fully type-annotated rational number library for Python.

Designed to integrate seamlessly with Python's numeric ecosystem while providing a clean, intuitive API for fraction arithmetic, comparison, conversion, and interoperability.

PyPI Version Python Versions License Tests Code Coverage Code Style Ruff Type Checked


Why Fraction?

Python already provides fractions.Fraction, but this library focuses on simplicity, readability, modern packaging, and developer experience.

It provides a clean immutable implementation that behaves naturally with Python's numeric types while remaining easy to understand, extend, and use in educational, scientific, and production projects.

Highlights include:

  • Automatic simplification
  • Immutable objects
  • Rich operator overloading
  • Strong type hints
  • Modern Python packaging
  • Comprehensive test suite
  • Excellent interoperability

Table of Contents

  • Features
  • Requirements
  • Installation
  • Quick Start
  • Creating Fractions
  • Arithmetic
  • Comparisons
  • Type Conversions
  • Utility Methods
  • Interoperability
  • API Overview
  • Project Structure
  • Development
  • Testing
  • Documentation
  • Roadmap
  • Contributing
  • License
  • Author

Features

Core Features

  • Pure Python implementation
  • Automatic reduction to lowest terms
  • Immutable design
  • Memory-efficient (__slots__)
  • Fully type annotated
  • PEP 561 compatible
  • Pickle support
  • Hashable objects

Supported Arithmetic

  • Addition
  • Subtraction
  • Multiplication
  • Division
  • Power operator
  • Unary operators
  • Reciprocal

Comparisons

  • Equality
  • Less than
  • Less than or equal
  • Greater than
  • Greater than or equal

Type Conversions

Supports conversion to

  • int
  • float
  • bool
  • round()

Alternative constructors

  • from_string()
  • from_float()
  • from_decimal()

Utility Methods

  • reciprocal()
  • mixed()
  • to_decimal()
  • as_tuple()

Interoperability

Works naturally with

  • int
  • float
  • fractions.Fraction
  • Python's numbers.Rational

Requirements

  • Python 3.10+
  • Pure Python
  • No runtime dependencies
  • Cross-platform
  • Fully typed

Installation

Install from PyPI

pip install fraction

Install from source

git clone https://github.com/Shravan4598/fraction.git

cd fraction

pip install -e .

Install development dependencies

pip install -r requirements-dev.txt

Verify Installation

>>> from fraction import fraction

>>> fraction(2, 4)
fraction(1, 2)

>>> fraction(5)
fraction(5, 1)

>>> fraction.from_string("3/9")
fraction(1, 3)

Quick Start

from fraction import fraction

a = fraction(1, 2)
b = fraction(3, 4)

print("a =", a)
print("b =", b)

print("Addition      :", a + b)
print("Subtraction   :", a - b)
print("Multiplication:", a * b)
print("Division      :", a / b)

print("Power         :", a ** 3)

print("Reciprocal    :", a.reciprocal())

print("Mixed Number  :", fraction(7, 3).mixed())

Output

a = 1/2
b = 3/4

Addition      : 5/4
Subtraction   : -1/4
Multiplication: 3/8
Division      : 2/3

Power         : 1/8

Reciprocal    : 2

Mixed Number  : (2, fraction(1, 3))

Design Goals

This project aims to provide a fraction implementation that is:

  • Easy to learn
  • Easy to read
  • Fully immutable
  • Type-safe
  • Fast enough for everyday use
  • Suitable for education
  • Suitable for production projects
  • Compatible with modern Python tooling

Creating Fractions

Fractions can be created in several ways depending on your data source.

Using the Constructor

from fraction import fraction

a = fraction(3, 4)
b = fraction(5)
c = fraction(-7, 9)

print(a)
print(b)
print(c)

Output

3/4
5
-7/9

Automatic Simplification

Fractions are always stored in their simplest form.

fraction(10, 20)

Output

fraction(1, 2)
fraction(-15, -30)

Output

fraction(1, 2)

Negative Denominator

The denominator is always kept positive.

fraction(2, -5)

Output

fraction(-2, 5)

Creating from Strings

fraction.from_string("7/9")

fraction.from_string("12")

fraction.from_string("-15/20")

Output

fraction(7, 9)

fraction(12, 1)

fraction(-3, 4)

Creating from Floats

fraction.from_float(0.75)

fraction.from_float(1.25)

Output

fraction(3, 4)

fraction(5, 4)

Creating from Decimal

from decimal import Decimal

fraction.from_decimal(
    Decimal("3.125")
)

Output

fraction(25, 8)

Arithmetic Operations

The class fully supports Python arithmetic operators.

Addition

a = fraction(1, 2)
b = fraction(2, 3)

print(a + b)

Output

7/6

Subtraction

print(
    fraction(5, 6) -
    fraction(1, 3)
)

Output

1/2

Multiplication

print(
    fraction(4, 5) *
    fraction(3, 7)
)

Output

12/35

Division

print(
    fraction(3, 5) /
    fraction(9, 10)
)

Output

2/3

Powers

x = fraction(2, 3)

print(x ** 2)

print(x ** 3)

print(x ** -2)

Output

4/9

8/27

9/4

Unary Operators

x = fraction(-2, 5)

print(+x)

print(-x)

print(abs(x))

Output

-2/5

2/5

2/5

Operations with Integers

Fractions work naturally with integers.

x = fraction(3, 4)

print(x + 2)

print(2 + x)

print(x - 1)

print(5 - x)

print(x * 4)

print(4 * x)

print(x / 2)

print(2 / x)

Comparison Operations

Fractions support all rich comparison operators.

fraction(1, 2) == fraction(2, 4)

fraction(3, 5) != fraction(4, 5)

fraction(1, 2) < fraction(2, 3)

fraction(7, 8) > fraction(5, 8)

fraction(4, 5) >= fraction(4, 5)

fraction(2, 3) <= fraction(5, 6)

Comparison with Integers

fraction(5, 2) > 2

fraction(1, 3) < 1

fraction(6, 2) == 3

Comparison with Float

fraction(1, 2) == 0.5

fraction(1, 4) < 0.5

fraction(7, 4) > 1.5

Type Conversions

The class integrates naturally with Python conversion functions.

Convert to Float

float(fraction(3, 8))

Output

0.375

Convert to Integer

Integer conversion truncates toward zero.

int(fraction(7, 3))

int(fraction(-7, 3))

Output

2

-2

Boolean Conversion

bool(fraction(1, 5))

bool(fraction(0, 9))

Output

True

False

Rounding

round(fraction(1, 3), 2)

round(fraction(5, 2))

Formatting

f = fraction(1, 3)

print(format(f, ".2f"))

print(format(f, ".5f"))

Utility Methods

Reciprocal

fraction(2, 5).reciprocal()

Output

fraction(5, 2)

Mixed Number

fraction(7, 3).mixed()

fraction(-7, 3).mixed()

fraction(-1, 3).mixed()

Output

(2, fraction(1, 3))

(-2, fraction(1, 3))

(0, fraction(-1, 3))

Decimal Representation

fraction(1, 3).to_decimal()

fraction(1, 3).to_decimal(5)

Output

0.33

0.33333

Tuple Representation

fraction(5, 8).as_tuple()

Output

(5, 8)

Interoperability

One of the design goals of this project is smooth interoperability with Python's built-in numeric types.

Built-in Fraction

from fractions import Fraction

a = fraction(2, 3)

b = Fraction(5, 7)

print(a + b)

print(a - b)

print(a * b)

print(a / b)

Integers

a = fraction(3, 4)

print(a + 5)

print(5 + a)

print(a * 10)

print(10 * a)

print(a / 2)

print(2 / a)

Hashability

Fractions are immutable and hashable, making them suitable as dictionary keys and set elements.

d = {
    fraction(1, 2): "half",
    fraction(2, 3): "two thirds",
}

print(d[fraction(2, 4)])

Output

half

Copy Support

Because fractions are immutable, copying returns the same object.

import copy

f = fraction(3, 4)

assert copy.copy(f) is f

assert copy.deepcopy(f) is f

API Reference

Constructor

fraction(numerator, denominator=1)

Creates a new immutable fraction.

fraction(3, 4)

fraction(10)

fraction(-5, 8)

Alternative Constructors

fraction.from_string()

Construct a fraction from a string.

fraction.from_string("5/8")

fraction.from_string("42")

fraction.from_float()

Construct from a floating-point number.

fraction.from_float(0.125)

fraction.from_decimal()

Construct from a Decimal.

from decimal import Decimal

fraction.from_decimal(
    Decimal("2.75")
)

Properties

numerator

Returns the numerator.

f = fraction(5, 8)

print(f.numerator)

Output

5

denominator

Returns the denominator.

f = fraction(5, 8)

print(f.denominator)

Output

8

Supported Operators

Arithmetic

Operator Description
+ Addition
- Subtraction
* Multiplication
/ Division
** Exponentiation

Comparison

Operator Description
== Equality
!= Not Equal
< Less Than
<= Less Than or Equal
> Greater Than
>= Greater Than or Equal

Unary

Operator Description
+ Unary Plus
- Unary Minus
abs() Absolute Value

Conversion Functions

Function Description
int() Convert to integer
float() Convert to float
bool() Truth value
round() Rounded value
format() String formatting

Utility Methods

Method Description
reciprocal() Returns reciprocal
mixed() Returns mixed number
to_decimal() Rounded decimal representation
as_tuple() Returns (numerator, denominator)

Design Principles

The library follows several important design goals.

  • Immutable objects
  • Automatic normalization
  • Consistent hashing
  • Strong type hints
  • Pythonic API
  • Interoperability with built-in numeric types
  • Memory efficiency using __slots__
  • Safe arithmetic
  • Production-ready packaging

Project Structure

fraction/
│
├── src/
│   └── fraction/
│       ├── __init__.py
│       ├── fraction.py
│       └── py.typed
│
├── tests/
│   ├── test_constructor.py
│   ├── test_arithmetic.py
│   ├── test_comparison.py
│   ├── test_conversion.py
│   ├── test_unary.py
│   ├── test_power.py
│   ├── test_utilities.py
│   ├── test_edge_cases.py
│   └── test_hash.py
│
├── examples/
│   ├── basic_usage.py
│   ├── arithmetic.py
│   ├── comparison.py
│   └── interoperability.py
│
├── docs/
│
├── .github/
│   └── workflows/
│
├── pyproject.toml
├── README.md
├── LICENSE
└── ...

Testing

The project uses pytest for testing.

Run all tests

pytest

Run with verbose output

pytest -v

Run a single file

pytest tests/test_arithmetic.py

Run a single test

pytest -k reciprocal

Generate coverage

pytest --cov=fraction

Generate HTML coverage report

pytest --cov=fraction --cov-report=html

The report will be available in

htmlcov/index.html

Code Quality

The project follows modern Python development practices.

Ruff

Run Ruff

ruff check .

Automatically fix issues

ruff check . --fix

Black

Format all files

black .

Check formatting

black . --check

MyPy

Run static type checking

mypy src

Pre-commit

Install hooks

pre-commit install

Run manually

pre-commit run --all-files

Development

Clone the repository

git clone https://github.com/Shravan4598/fraction.git

Move into the project

cd fraction

Create a virtual environment

python -m venv .venv

Activate it

Linux / macOS

source .venv/bin/activate

Windows

.venv\Scripts\activate

Install dependencies

pip install -r requirements-dev.txt

Install the package in editable mode

pip install -e .

Building the Package

Build a source distribution and wheel

python -m build

Generated files

dist/

fraction-x.x.x.tar.gz

fraction-x.x.x-py3-none-any.whl

Publishing to PyPI

Upload using Twine

twine upload dist/*

If Trusted Publishing is configured, GitHub Actions can publish automatically when a release is created.


Continuous Integration

GitHub Actions automatically performs:

  • Code formatting checks
  • Ruff linting
  • MyPy type checking
  • Unit testing
  • Coverage generation
  • Package building
  • Distribution validation

Every pull request and push is validated before merging.


Documentation

Documentation is generated using MkDocs Material.

Serve locally

mkdocs serve

Build the documentation

mkdocs build

Deploy to GitHub Pages

mkdocs gh-deploy

The documentation includes:

  • Installation Guide
  • API Reference
  • Examples
  • Changelog
  • Development Guide

Performance

The fraction package is designed to be lightweight, efficient, and predictable.

Characteristics

  • Immutable objects
  • Hashable
  • Automatic normalization using math.gcd()
  • Memory efficient (__slots__)
  • Fully type annotated
  • Pure Python
  • No runtime dependencies

Most arithmetic operations execute in constant time apart from the cost of integer arithmetic and the GCD calculation required for normalization.


FAQ

Why not use fractions.Fraction?

Python's built-in fractions.Fraction is an excellent implementation.

This project is intended to provide:

  • A clean educational implementation
  • Modern project structure
  • Strong typing
  • Easy-to-read source code
  • Examples for learning operator overloading
  • A reusable open-source package

Is the class immutable?

Yes.

After construction, neither the numerator nor denominator can be modified.


Are fractions automatically simplified?

Yes.

fraction(20, 60)

becomes

fraction(1, 3)

Can I use fractions as dictionary keys?

Yes.

prices = {
    fraction(1, 2): "Half",
    fraction(1, 4): "Quarter",
}

print(prices[fraction(2, 4)])

Output

Half

Does it support negative fractions?

Yes.

fraction(-2, 5)

fraction(2, -5)

fraction(-2, -5)

All signs are normalized automatically.


Does it support Decimal?

Yes.

from decimal import Decimal

fraction.from_decimal(
    Decimal("3.125")
)

Does it work with Python integers?

Yes.

fraction(1, 2) + 5

5 + fraction(1, 2)

fraction(3, 4) * 8

8 / fraction(3, 4)

Is the project thread-safe?

Yes.

Because the objects are immutable, they can safely be shared across threads.


Roadmap

The following features are planned for future releases.

Version 1.x

  • Additional constructors
  • Better formatting options
  • JSON serialization helpers
  • More mathematical utilities
  • Improved interoperability

Version 2.x

  • Performance benchmarking
  • NumPy interoperability
  • SymPy interoperability
  • Optional C extension
  • Rich string formatting

Long-term Goals

  • Stable public API
  • 100% documentation coverage
  • 100% test coverage
  • Continuous benchmarking
  • Community contributions
  • Educational examples
  • Interactive documentation

Contributing

Contributions are welcome and greatly appreciated.

You can contribute by

  • Reporting bugs
  • Suggesting features
  • Improving documentation
  • Writing tests
  • Improving examples
  • Optimising performance

Please read

  • CONTRIBUTING.md
  • CODE_OF_CONDUCT.md

before opening a pull request.


Reporting Issues

If you discover a bug, please create a GitHub Issue including

  • Python version
  • Operating system
  • Package version
  • Minimal reproducible example
  • Expected behaviour
  • Actual behaviour

This helps us resolve issues more quickly.


Security

If you discover a security vulnerability, please do not open a public issue.

Instead, follow the instructions in SECURITY.md.

We appreciate responsible disclosure.


Versioning

This project follows Semantic Versioning (SemVer).

Version numbers follow the format

MAJOR.MINOR.PATCH

Example

1.0.0

Changelog

Release history is maintained in

CHANGELOG.md

License

This project is distributed under the MIT License.

You are free to

  • Use
  • Modify
  • Distribute
  • Include in commercial projects

subject to the terms of the MIT License.

See the LICENSE file for complete details.


Acknowledgements

This project is inspired by

  • Python's fractions module
  • The Python Standard Library
  • PEP 3141 — Numeric Tower
  • The open-source Python community

Special thanks to all contributors and users who help improve this project.


Author

Shravan Kumar Pandey

Computer Science & Engineering (Data Science)

GitHub

https://github.com/Shravan4598

LinkedIn

(Add your LinkedIn profile URL here once available.)


Citation

If you use this project in research, teaching, or publications, please consider citing it.

BibTeX support may be added in future releases.


Support the Project

If you find this project useful, you can help by

  • ⭐ Starring the repository
  • 🐛 Reporting issues
  • 💡 Suggesting new features
  • 📖 Improving documentation
  • 🧪 Writing tests
  • 🔀 Submitting pull requests

Every contribution, no matter how small, is appreciated.


Maintainer

Shravan Kumar Pandey

GitHub: https://github.com/Shravan4598


⭐ If you find this project useful, please consider giving it a star on GitHub!

Made with ❤️ using Python.

Metadata

Release files for fraction-py 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fraction-py 1.0.0
File Size Uploaded
fraction_py-1.0.0.tar.gz 41.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fraction-py 1.0.0
File Interpreter ABI Platform
fraction_py-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 53.7 kB

Release files / fraction_py-1.0.0.tar.gz

Download URL fraction_py-1.0.0.tar.gz
Size 41.8 kB
Tags Source
SHA-256 checksum
How to use checksums
b692fa7aef968f526b51e03f97670e5ac3660b443c145f6553d1a351eb7ae1a4
BLAKE2b-256 checksum
How to use checksums
6e3f877128b728485b525d69a315a043a4bc12bbd872907cfa451be02ad01550
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.7

Release files / fraction_py-1.0.0-py3-none-any.whl

Download URL fraction_py-1.0.0-py3-none-any.whl
Size 11.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
01d54ef64db6c9734a47141d3ff393c8470aa3d1a8fbe181007c2294f42f7825
BLAKE2b-256 checksum
How to use checksums
8db1fd8bb19ee1144e5146d7961f58afbf356b83e601e77abe25ee5e45017455
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.7

Release history Release notifications | RSS feed

1.0.2

2 release files

1.0.1

2 release files

This release

1.0.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page