Method Overloading in Python (with Examples)

Method overloading refers to defining multiple methods with the same name but different signatures (parameters) within the same class.

In Python, method overloading is not supported in the traditional sense like in some other languages (e.g., Java or C++), but we can simulate it by using default arguments or by checking the type and number of arguments within the method. In this article, we will discuss different techniques to achieve method overloading-like behavior in Python.

Method Overloading in Python

There are multiple techniques that we can use for method overloading in Python.

  1. Default Arguments – We define parameters with default values. Default values allow flexibility with fewer arguments.
  2. Variable-Length Arguments (*args and **kwargs) – This helps to handle an arbitrary number of arguments.
  3. Type Checking with isinstance – Handles different types within the same method.
  4. Function Dispatching with functools.singledispatch – Overload based on the type of the first argument.
  5. Custom Logic – Write custom methods that handle different parameter combinations.
  6. External Libraries – Use libraries like multipledispatch for more advanced overloading. Using multipledispatch provides the true method overloading very similar to method overloading in other programming languages.

Method Overloading – Using Default Arguments

By providing default values for parameters, a method can be called with different numbers of arguments.

Example of Method Overloading Using Default Arguments

class MathOperations:
    def add(self, a, b=0, c=0):         # default values to b & c parameters
        return a + b + c

math_op = MathOperations()
print(math_op.add(15))                  # Output => 15 (one argument)
print(math_op.add(5, 30))         # Output => 35 (two arguments)
print(math_op.add(5, 30, 25))  # Output => 60 (three arguments)

In this example, add(self, a, b=0, c=0) method has three parameters a, b & c. b & c are given default value 0. because of parameters default value, we can call this method either using one argument or two arguments or three arguments.

Method Overloading – Using Variable-Length Arguments (*args and **kwargs)

We can use *args for a variable number of positional arguments and **kwargs for keyword arguments to handle different method signatures.

  • Use *args for variable number of positional arguments
  • Use **kwargs for variable number of keyword arguments

Example with *args

class MathOperations:
    def add(self, *args):            # *args allows variable number of arguments
        sum = 0
        for num in args:
            sum += num
        return sum

math_op = MathOperations()
print(math_op.add(15))               # Output => 15 (one argument)
print(math_op.add(5, 30))      # Output => 35 (two arguments)
print(math_op.add(5, 30, 25))  # Output => 60 (three arguments)

In this example, we have defined a function add(self, *args) which takes variable number of arguments. We are loop through the number of arguments and calculate the total sum. We can call this method using n number of arguments. We are calling this method using one argument or two arguments or three arguments.

Example with *args and **kwargs

class MathOperations:
    def operation(self, *args, **kwargs):      # **kwargs allows variable number of keyword arguments
        if kwargs.get('operation') == 'multiply':  # Perform multiplication
            result = 1
            for num in args:
                result *= num
            return result
        else:                                     # Default to addition
            result = 0
            for num in args:
                result += num
            return result

math_op = MathOperations()
print(math_op.operation(2, 3))                        # Output => 5 (default: sum)
print(math_op.operation(2, 3, operation='multiply'))  # Output => 6 (multiplication)

In this example, we have defined a function operation(self, *args, **kwargs) which takes variable number of positional arguments and variable number of keyword arguments. **kwargs arguments can be used to handle multiple scenarios. Based on the key-value pair given for **kwargs, we can perform different operations. math_op.operation(2, 3, operation='multiply') calls with 2 positional arguments and 1 keyword argument.

Method Overloading – Using Type Checking (isinstance)

Using isinstance we can check the types of the arguments inside the method and decide what action to taken based on that.

Syntax – isinstance(variable, datatype) => This returns True of variable is of same datatype and False if variable if of different datatype.

# Method Overloading - Using Type Checking (isinstance)
class InstanceOperations:
    def concat_or_multiply(self, a, b):
        if isinstance(a, str) and isinstance(b, str):   # check for both parameter value as str
            return a + b     # If str, perform concatenation
        elif isinstance(a, int) and isinstance(b, int): # check for both parameter value as int
            return a * b     # If int, perform multiplication
        else:
            raise "UnsupportedTypesError"  # error, if both parameters are of different type

instance_op = InstanceOperations()
print(instance_op.concat_or_multiply(5, 10))                     # Output: 50
print(instance_op.concat_or_multiply("Python", "@shbytes.com"))  # Output: Python@shbytes.com

In this example, concat_or_multiply(self, a, b) function takes two arguments and isinstance(variable, datatype) checks for the instance type of each argument. Based on either both the arguments are str, performs concatenation and if both arguments are int then it performs multiplication.

Method Overloading – Using Function Dispatching (functools.singledispatch)

Python’s functools.singledispatch allows us to overload a function based on the type of the first argument. It doesn’t allow overloading based on multiple arguments but works well for single-argument functions.

  • @singledispatch => Single-dispatch generic function decorator. Transforms a function into a generic function, which can have different behaviors depending upon the type of its first argument. The decorated function acts as the default implementation, and additional implementations can be registered using the register() attribute of the generic function.
  • @method_name.register(int) => This registers given method_name for int datatype argument
  • @method_name.register(str) => This registers given method_name for str datatype argument
# Method Overloading - Using Function Dispatching (functools.singledispatch)
from functools import singledispatch  # import singledispatch from functools module

@singledispatch  # Single-dispatch generic function decorator
def add(a):      # define default definition for add(a) function
    raise NotImplementedError("Unsupported type")

@add.register(int)  # register add(variable) function for int datatype argument
def _(a):           # function definition for int datatype argument
    return a + 10

@add.register(str)  # register add(variable) function for str datatype argument
def _(a):           # function definition for str datatype argument
    return a + "@shbytes.com"

print(add(15))         # Output: 25
print(add("PowerBI"))  # Output: PowerBI@shbytes.com
  • @singledispatch on add(a) defines a dispatch function with default definition for add(a) function
  • @add.register(int) registers add(a) function for int datatype argument and _(a) provides function definition in case of int datatype argument.
  • @add.register(str) registers add(a) function for str datatype argument and _(a) provides function definition in case of str datatype argument.

Method Overloading – Using Custom Logic

We can implement custom logic that handles different combinations of arguments or types within a single method. Custom logic implementation is very similar to default arguments.

# Method Overloading - Using Custom Logic
class MathOperations:
    def add(self, a, b=None, c=None):  # function definition with b & c default to None
        if b is None and c is None:    # check if b & c both are None
            return a
        elif c is None:                # check if c is None
            return a + b               # addition of 2 parameters
        else:
            return a + b + c           # addition of 3 parameters

math_op = MathOperations()
print(math_op.add(50))                   # Output: 50 (one argument)
print(math_op.add(50, 20))         # Output: 75 (two arguments)
print(math_op.add(50, 20, 45))  # Output: 115 (three arguments)

Method Overloading – Using External Libraries (multipledispatch)

We can use third-party libraries like multipledispatch to achieve true function/method overloading based on the number and types of arguments.

pip install multipledispatch => Install multipledispatch module

# Method Overloading - Using External Libraries (multipledispatch)
from multipledispatch import dispatch  # import dispatch from multipledispatch module

class MathOperations:
    @dispatch(int, int)  # define function for both parameters int
    def add(self, a, b):        # function definition for both parameters int
        return a + b

    @dispatch(str, str)  # define function for both parameters str
    def add(self, a, b):        # function definition for both parameters str
        return a + " " + b

    @dispatch(int, str)  # define function for parameters int & str
    def add(self, a, b):        # function definition for parameters int & str
        return "Unsupported datatype"

math_op = MathOperations()
print(math_op.add(50, 10))                      # Output: 60
print(math_op.add("PowerBI", "@shbytes.com"))   # Output => PowerBI @shbytes.com
print(math_op.add(10, "random"))                # Output => Unsupported datatype
  • @dispatch(int, int) => Annotation used on function for both parameters int
  • @dispatch(str, str) => Annotation used on function for both parameters str
  • @dispatch(int, str) => Annotation used on function for parameters int & str

Summary

In this article, we learned about various techniques for Method Overloading in Python. Following techniques were discussed:

Code – Github Repository

All code snippets and programs for this article and for Python tutorial, can be accessed from Github repository – Comments and Docstring in Python.

Python Topics


Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *