'How to avoid overuse of **kwargs in situation when passing function that takes differing arguments to another function?

I have a function like so:

def outer_function(input1, input2, func):
    a = ....[calculations that depend on input1 and input2]....
    b = ....[calculations that depend on input1 and input2]....
    c = ....[calculations that depend on input1 and input2]....
    d = func(a=a, b=b, c=c)

    return d

where I can pass either func1 or func2 into the outer_function as the argument func. The problem is that func1 actually only depends on a and b, and so can be written like

def func1(**kwargs):
    a = kwargs.get('a')
    b = kwargs.get('b')
    
    return something_with_a_and_b

Meanwhile, func2 depends on all 3 values, like so:

def func2(**kwargs):
    a = kwargs.get('a')
    b = kwargs.get('b')
    c = kwargs.get('c')
    return something_with_a_and_b_and_c

This works, but I don't like it because it requires me to pass a lot of stuff (in my actual case) as arguments to func within outer_function that aren't always used by the actual routine, and so it obscures what my routines actually depend upon (and instead you have to look at what values I'm accessing from **kwargs. Is there a better way to handle this type of situation? I have a cleaner implementation as a class, but I need a functional approach in this specific situation.



Solution 1:[1]

A cleaner way to habdle this is make decorators to handle custom composition of functions. There is not a unique solution since it depdens on the order of composition. Here an example

def a(i1, i2): return [i1**1 for i1 in range(i2)]
def b(i1, i2): return [i1**2 for i1 in range(i2)]
def c(i1, i2): return [i1**3 for i1 in range(i2)]

def power_of_2(data: list):
    return [i+2 for i in data]
    
def composer(input1, input2):
    def wrapper(*funcs):  # funcs are a, b, c, ...
        def wrapper2(func): # f is the final function
            return func(sum([f(input1, input2) for f in funcs], [])) # sum flat the list
        return wrapper2
    return wrapper

test1 = composer(3, 4)(a, b)(power_of_2)
print(test1)
test2 = composer(3, 4)(a, b, c)(power_of_2)
print(test2)

Output

[2, 3, 4, 5, 2, 3, 6, 11]
[2, 3, 4, 5, 2, 3, 6, 11, 2, 3, 10, 29]

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1