Skip to main content

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.

Python 3.9+ License: MIT PyPI

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:

  1. Registration - Each @overload decorated function is registered with its type signature
  2. Resolution - When called, MethodOverload examines the argument types
  3. Matching - Finds the implementation whose type signature matches the arguments
  4. Execution - Calls the matching implementation
  5. 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, NoMatchingOverloadError is 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

  1. OverloadedFunction - Container for multiple implementations with dispatch logic
  2. @overload Decorator - Registers function implementations
  3. OverloadMeta Metaclass - Merges overloads in class definitions
  4. 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 like List[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:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes
  4. Add tests for new functionality
  5. 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

Metadata

Release files for methodoverload 0.1.7

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

Source distribution (sdist)

Source distribution for methodoverload 0.1.7
File Size Uploaded Provenance
methodoverload-0.1.7.tar.gz 15.9 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for methodoverload 0.1.7
File Interpreter ABI Platform
methodoverload-0.1.7-py3-none-any.whl Python 3 none any Details

Total release size: 28.7 kB

Release files / methodoverload-0.1.7.tar.gz

Download URL methodoverload-0.1.7.tar.gz
Size 15.9 kB
Tags Source
SHA-256 checksum
How to use checksums
e909536b9356d3958f63a8059de5eb65a1e201723013847712d80ca052ec122f
BLAKE2b-256 checksum
How to use checksums
8a24381b81ee021ef58b374567d4a4d93aff5d3a56892eca06c85bfd81091666
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Release files / methodoverload-0.1.7-py3-none-any.whl

Download URL methodoverload-0.1.7-py3-none-any.whl
Size 12.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
aa550278ab545dd77dbc7cf31cde418b82cfb80d9f44e1885bb002dd1f97e281
BLAKE2b-256 checksum
How to use checksums
a791be01b31f27c79bec9149a1e6f064f19e64d217fd127926301a27bdba70a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.9

Security for methodoverload 0.1.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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