Search code examples
pythonargumentswrapper

Change only certain arguments in a class/method, hold others constant


I have a class & method, each with several arguments: my_class(a,b,c).my_method(d,e,f) and I'd like to be able to only change a single argument, while holding the others constant.

Constantly copy-pasting the other constant arguments seems bad, so I'd like to create a new object wrapper_fct where I reference my_class but only provide the one argument I want to change, b, without always having to specify the remaining arguments. How would wrapper_fct() look like?

For example, wrapper_fct(my_class, b1) would return my_class(a,b1,c).my_method(d,e,f), wrapper_fct(my_class, b2) would return my_class(a,b2,c).my_method(d,e,f).

Here's an example in practice:

Loop through just the variable b and evaluate several classes/methods for each new instance of b, and append the results in a list. I can currently do this in a for loop:

mylist1 = [] # init lists (append results here)
mylist2 = []
mylist2 = []

for b in  [1,2,3,4,5]:
   mylist1.append( my_class1(a,b,c).my_method(d,e,f) )
   mylist2.append( my_class2(a,b,c).my_method(d,e,f) )
   mylist3.append( my_class3(a,b,c).my_method(d,e,f) )
   ...

But it seems better to create a function loop_through_B() and use the wrapper_fct(my_class,b) as specified above. Not sure if it's the ideal solution, but maybe something like:

def loop_through_B(input_class, b_values = [1,2,3,4,5])
    mylist = []
    for b in b_values:
        mylist.append( wrapper_fct(input_class,b) )
    return mylist        

loop_through_B(my_class1) # would I also have to specify the method here as well?
loop_through_B(my_class2)
loop_through_B(my_class3)

Extra Question: how would I add the ability to vary method arguments, or even multiple class & method arguments?


Solution

  • After @chepner pointed me in the right direction, I think the best solution is to use the lambda function:

    wrapper_fct = lambda b: my_class1(a,b,c).my_method(d,e,f)
    

    In this case, I can vary b as much as I want while holding the class arguments a,c, and method arguments d,e,f constant. Note that with lambda functions, I can also vary the method arguments and/or the class arguments. For example:

    wrapper_fct_multiple = lambda b, e: my_class1(a,b,c).my_method(d,e,f)
    

    It is also possible to do this with functools.partial, but it's not obvious to me how I would specify both class & method arguments with functools.

    Anyway, here is the solution implementation using lambda:

    # define the "wrapper function" outside the loop
    wrapper_fct = lambda b: my_class1(a,b,c).my_method(d,e,f)
    
    # define the function I want to use to loop through B:
    def loop_through_B(class_wrapper, b_values)
        mylist = []
        for b in b_values:
            mylist.append( class_wrapper(b) )
        return mylist  
    
    # run:
    loop_through_B(wrapper_fct, b_values=[1,2,3,4,5])
    
    # Can make additional wrapper_fct2, wrapper_fct3, for my_class2, my_class3 ...