Is there a Python language feature that enables a function to be called with different (but known) parameter combinations?

Viewed 45

Consider the following functions:

def function_a(self, index):
    # ..do something with index and return the result
    return index * index


def function_b(self, group, arg):
    # ..do something with group and arg to derive an index and call function_a
    index = group + arg
    return function_a(index)


def function_c(self, group, arg_mult):
    # ..do something with group and arg_mult to derive an index and call function_a
    index = group * arg_mult
    return function_a(index)

Assume there are multiple functions in this module that take an index as parameter. Each of those functions should be callable with other parameter combinations which are then converted into an index with which the original function is called. The allowed combinations of parameters are the same for each function (in the example above: group and arg or group and arg_mult). I wrote a decorator for that called convert_parameters and decorated function_a with it. function_b and function_c can then be omitted.

import functools


def convert_parameters(func):
    @functools.wraps(func)
    def wrapper(self, *args, arg_index=None, group=None, arg=None, arg_mult=None, **kwargs):
        index = None

        if arg_index is not None:
            index = arg_index

        elif group is not None:
            if arg is not None:
                index = group + arg
            elif arg_mult is not None:
                index = group * arg_mult
        
        if index is None:
            raise ValueError("invalid parameter combination provided.")
        return func(self, *args, index=index, **kwargs)
    return wrapper

@convert_parameters
def function_a(self, index):
    # ..do something with index and return the result
    return index * index

However, I am not sure if this is a very elegant solution, since the caller must know which argument combinations are valid for function_a (or any other function decorated with convert_parameters). This would basically require a look into the code. I would rather have it that the valid signatures for those functions are known to the caller, much like emulating the behavior of @overload but with my custom decorator.

1 Answers

Actually you dont need use decorator to call with different (but known) parameter combinations.

code:

def caller(index,**kwargs):
    if not kwargs:
        return func_a(index)
    elif "group" in kwargs and "arg" in kwargs:
        return func_a(kwargs["group"] + kwargs["arg"])
    elif "group" in kwargs and "arg_mult" in kwargs:
        return func_a(kwargs["group"] * kwargs["arg_mult"])
    else:
        raise ValueError("invalid parameter combination provided.")

def func_a(index):
    return index * index

print(caller(5))
print(caller(5, group = 10, arg = 15))
print(caller(5, group = 3, arg_mult = 4))
try:
    print(caller(5, group = 5, arg_mul = 4))
except ValueError as e:
    print(e)
try:  
    print(caller(5, grou = 3, arg_mul = 4))
except ValueError as e:
    print(e)

result:

25
625
144
invalid parameter combination provided.
invalid parameter combination provided.

If you must use decorator,basically same code:

def convert_parameters(func):
    def wrapper(index, **kwargs):
        if not kwargs:
            return func(index)
        elif "group" in kwargs and "arg" in kwargs:
            return func(kwargs["group"] + kwargs["arg"])
        elif "group" in kwargs and "arg_mult" in kwargs:
            return func(kwargs["group"] * kwargs["arg_mult"])
        else:
            raise ValueError("invalid parameter combination provided.")
    return wrapper

@convert_parameters
def function_a(index):
    return index * index

print(function_a(5))
print(function_a(5, group = 10, arg = 15))
print(function_a(5, group = 3, arg_mult = 4))
try:
    print(function_a(5, group = 5, arg_mul = 4))
except ValueError as e:
    print(e)
try:  
    print(function_a(5, grou = 3, arg_mul = 4))
except ValueError as e:
    print(e)

result:

25
625
144
invalid parameter combination provided.
invalid parameter combination provided.
Related