Skip to main content

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.

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

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

methodoverload-0.1.7.tar.gz (15.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

methodoverload-0.1.7-py3-none-any.whl (12.7 kB view details)

Uploaded Python 3

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

Hashes for methodoverload-0.1.7.tar.gz
Algorithm Hash digest
SHA256 e909536b9356d3958f63a8059de5eb65a1e201723013847712d80ca052ec122f
MD5 055ff02e388b2728ea5ac52514021d45
BLAKE2b-256 8a24381b81ee021ef58b374567d4a4d93aff5d3a56892eca06c85bfd81091666

See more details on using hashes here.

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

Hashes for methodoverload-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 aa550278ab545dd77dbc7cf31cde418b82cfb80d9f44e1885bb002dd1f97e281
MD5 837f099884371185af665641a5945c0d
BLAKE2b-256 a791be01b31f27c79bec9149a1e6f064f19e64d217fd127926301a27bdba70a7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page