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.
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
intfloatboolround()
Alternative constructors
from_string()from_float()from_decimal()
Utility Methods
reciprocal()mixed()to_decimal()as_tuple()
Interoperability
Works naturally with
intfloatfractions.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
fractionsmodule - 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
(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
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)
| File | Size | Uploaded | |
|---|---|---|---|
| fraction_py-1.0.0.tar.gz | 41.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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
|