Search code examples
pythoniterable-unpacking

Unpacking different numbers of variables


I want to make a function that is flexible with regard to unpacking the number of input variables.

More specifically, for example I have the following:

def flexi_func(vars):
    func_var_a, func_var_b, func_var_c, func_var_d = vars
    #do something

my_vars = [var_a, var_b, var_c, var_d]
flexi_func(my_vars)

This works fine if the number of input variables is 4. But say I want to have the same function operate on just three input variables, or two. Assume the 'do something' bit is already flexible. Then to unpack the variables I can write

def flexi_func(vars):
    if len(vars) == 4:
        func_var_a, func_var_b, func_var_c, func_var_d = vars
    elif len(vars) == 3:
        func_var_a, func_var_b, func_var_c = vars
    elif len(vars) == 2:
        func_var_a, func_var_b = vars
    #do something

And this works fine too. It just seems a bit clunky to me, especially if I had N>4 variables. Is there a cleaner, more Pythonic way to unpack a tuple in such a way that I can use the unpacked variables?

I know from this question I can do something like this (in Python 3):

foo, bar, *other = func()

but I would need to do more work to access the stuff in other, so it's no better than my if...elif... approach.


Solution

  • Firstly, in response to the comments asking for context or a concrete example where this might be necessary, I concede that in almost all the cases I can think of it should be possible to avoid unpacking altogether. This goes for my original problem too - the do something part of the function can be modified to access the items through list indices.

    However, in principle, I am sure there exist situations where unpacking is needed, even if only for clarity. Below is the best way I can find to assign a variable to each input item. More background detail is given in the answers here and here.

    def flexi_func(var_list):    
        for i, var in enumerate(var_list):
            vars()['my_func_{}'.format(i)] = var
    
        #do something 
    
        return
    

    This assigns each input variable to the vars() built-in dictionary. This is preferable to the globals() built-in dictionary and is writable unlike the locals() built-in dictionary. To access the variables in the do something section, you have to reference the dictionary like so: print(vars()['my_func_2']).

    Finally, if you want to use letters as variable labels instead of numbers (as I did in my problem statement) you can add alphabet = [chr(i) for i in range(ord('a'),ord('z')+1)] to the top of the function and call the variables 'my_func_{}'.format(alphabet[i]).