Runtime function and method overloading for Python
Project description
MethodOverload - Function and Method Overloading for Python
A powerful Python library that brings function and method overloading to Python, allowing you to define multiple implementations of the same function with different type signatures. Overloading is resolved at runtime based on the types of arguments passed.
Why MethodOverload?
Python doesn't natively support function overloading like Java or C++. If you define two functions with the same name, the second one overwrites the first. MethodOverload solves this problem elegantly:
# Without MethodOverload - This doesn't work!
def add(a: int, b: int):
return a + b
def add(a: str, b: str): # Overwrites the previous function!
return f"{a} {b}"
# With MethodOverload - This works perfectly!
from methodoverload import overload
@overload
def add(a: int, b: int):
return a + b
@overload
def add(a: str, b: str):
return f"{a} {b}"
print(add(1, 2)) # Output: 3
print(add("Hello", "World")) # Output: Hello World
Features
✨ Simple & Intuitive - Just use the @overload decorator
✨ Type-Safe - Automatically matches the correct implementation based on type hints
✨ Instance Methods - Full support for instance methods with metaclass integration
✨ Class Methods - Works seamlessly with @classmethod
✨ Static Methods - Compatible with @staticmethod
✨ Caching - Fast resolution with built-in caching mechanism
✨ Clear Error Messages - Helpful error messages when no matching overload is found
Installation
Install from PyPI:
pip install methodoverload
Or from source:
git clone https://github.com/mohdcodes/pyoverload.git
cd methodoverload
pip install -e .
Quick Start
1. Basic Function Overloading
from methodoverload import overload
@overload
def process(data: int):
return data * 2
@overload
def process(data: str):
return data.upper()
@overload
def process(data: list):
return len(data)
print(process(5)) # Output: 10
print(process("hello")) # Output: HELLO
print(process([1, 2, 3])) # Output: 3
2. Instance Methods with Metaclass
from methodoverload import overload, OverloadMeta
class Calculator(metaclass=OverloadMeta):
@overload
def compute(self, a: int, b: int):
return a + b
@overload
def compute(self, a: str, b: str):
return f"{a}{b}"
@overload
def compute(self, a: list, b: list):
return a + b
calc = Calculator()
print(calc.compute(1, 2)) # Output: 3
print(calc.compute("Hello", "World")) # Output: HelloWorld
print(calc.compute([1, 2], [3, 4])) # Output: [1, 2, 3, 4]
3. Class Methods
from methodoverload import overload, OverloadMeta
class Greeter(metaclass=OverloadMeta):
@overload
@classmethod
def greet(cls, name: str):
return f"Hello {name}"
@overload
@classmethod
def greet(cls, count: int):
return f"Greeting #{count}"
print(Greeter.greet("Alice")) # Output: Hello Alice
print(Greeter.greet(42)) # Output: Greeting #42
4. Static Methods
from methodoverload import overload, OverloadMeta
class Math(metaclass=OverloadMeta):
@overload
@staticmethod
def multiply(a: int, b: int):
return a * b
@overload
@staticmethod
def multiply(a: float, b: float):
return round(a * b, 2)
print(Math.multiply(3, 4)) # Output: 12
print(Math.multiply(3.5, 2.5)) # Output: 8.75
How It Works
MethodOverload uses type hints to determine which implementation to call:
- Registration - Each
@overloaddecorated function is registered with its type signature - Resolution - When called, MethodOverload examines the argument types
- Matching - Finds the implementation whose type signature matches the arguments
- Execution - Calls the matching implementation
- Caching - Results are cached for performance
Type Matching Rules
- Arguments are matched against type hints using
isinstance() - The first matching overload is called
- If no overload matches,
NoMatchingOverloadErroris raised
from methodoverload import overload
@overload
def process(data: str):
return f"String: {data}"
@overload
def process(data: int):
return f"Integer: {data}"
# This works!
process("hello") # Output: String: hello
process(42) # Output: Integer: 42
# This raises NoMatchingOverloadError
process(3.14) # No matching overload for float!
Advanced Usage
Multiple Type Parameters
from methodoverload import overload
@overload
def convert(value: int, to_type: str):
return str(value)
@overload
def convert(value: str, to_type: int):
return int(value)
@overload
def convert(value: list, to_type: tuple):
return tuple(value)
print(convert(42, "str")) # Output: "42"
print(convert("100", "int")) # Output: 100
print(convert([1, 2, 3], tuple)) # Output: (1, 2, 3)
Combining with Other Decorators
from methodoverload import overload
@overload
def cached_process(data: int):
print("Processing integer...")
return data ** 2
@overload
def cached_process(data: str):
print("Processing string...")
return data.upper()
# Each call with the same type is cached for performance
print(cached_process(5)) # Processing integer...
print(cached_process(5)) # (cached - no print)
Error Handling
When no matching overload is found, you get a helpful error message:
from methodoverload import overload, NoMatchingOverloadError
@overload
def add(a: int, b: int):
return a + b
try:
add("1", "2") # No string overload defined
except NoMatchingOverloadError as e:
print(e)
# Output: No matching overload found for 'add' with args=('1', '2'), kwargs={}
Examples
See the examples/ directory for more detailed examples:
- basic.py - Free function overloading
- classmethod.py - Class method overloading
- staticmethod.py - Static method overloading
- types.py - Complex type examples
Run an example:
python -m examples.basic
Architecture
Core Components
- OverloadedFunction - Container for multiple implementations with dispatch logic
- @overload Decorator - Registers function implementations
- OverloadMeta Metaclass - Merges overloads in class definitions
- OverloadCache - Caches resolved overloads for performance
Design Principles
- Framework-agnostic - No dependencies, works with any Python code
- Type-driven - Uses type hints for dispatch
- Descriptor protocol - Integrates seamlessly with Python's method binding
- Efficient - Built-in caching for repeated calls
Limitations & Best Practices
Current Limitations
- Overloads are resolved at runtime (not compile-time)
- Only supports positional and keyword arguments
- Type matching uses
isinstance()(no generic types likeList[int])
Best Practices
✓ Always use type hints for all parameters
✓ Keep implementations focused and simple
✓ Use descriptive function names
✓ Test all overload combinations
✓ Document which types are supported
# Good
@overload
def process(data: str) -> str:
"""Process string data and return uppercase."""
return data.upper()
# Avoid - Missing type hints
@overload
def process(data):
return data.upper()
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes
- Add tests for new functionality
- Submit a pull request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Authors
- Mohd Arbaaz Siddiqui - Original author
- See Contributors for the full list
Support
Changelog
Version 0.1.0 (Current)
- Initial release
- Free function overloading
- Instance method overloading with OverloadMeta
- Class method and static method support
- Built-in caching for performance
- Type hint-based dispatch
- Comprehensive error messages
Citation
If you use MethodOverload in your research or project, please cite:
@software{methodoverload2024,
title={MethodOverload: Function and Method Overloading for Python},
author={Siddiqui, Mohd Arbaaz},
year={2024},
url={https://github.com/mohdcodes/pyoverload}
}
Made with ❤️ by MOHD ARBAAZ SIDDIQUI
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file methodoverload-0.1.7.tar.gz.
File metadata
- Download URL: methodoverload-0.1.7.tar.gz
- Upload date:
- Size: 15.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e909536b9356d3958f63a8059de5eb65a1e201723013847712d80ca052ec122f
|
|
| MD5 |
055ff02e388b2728ea5ac52514021d45
|
|
| BLAKE2b-256 |
8a24381b81ee021ef58b374567d4a4d93aff5d3a56892eca06c85bfd81091666
|
File details
Details for the file methodoverload-0.1.7-py3-none-any.whl.
File metadata
- Download URL: methodoverload-0.1.7-py3-none-any.whl
- Upload date:
- Size: 12.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aa550278ab545dd77dbc7cf31cde418b82cfb80d9f44e1885bb002dd1f97e281
|
|
| MD5 |
837f099884371185af665641a5945c0d
|
|
| BLAKE2b-256 |
a791be01b31f27c79bec9149a1e6f064f19e64d217fd127926301a27bdba70a7
|