In python I often see functions with a lot of arguments. For example:
def translate(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p):
// some code
return(x, y, z)
I like this pattern in some cases. I think it makes a ton of sense in library type situations where the variables are optional keyword arguments (e.g. pd.DataFrame declarations).
However, I also see instances (locally developed custom functions) where where all of the inputs are essentially mandatory. In these cases the function is typically called elsewhere in the program and will be formatted something along the lines of:
x, y, z = translate(a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
I dislike several things about this:
- Readability - the function call ends up being very long, which makes it hard to read/digest and can sometimes obstruct the readability of the script it is sitting in
- Re-use of variable names - the local variable
a
intranslate()
is not the same entity as the variablea
in the script - Jumbled variables - it is very easy to accidentally write
translate(b, a, c, d, e, f, g, h, i, j, k, l, m, n, o, p)
because most variable names don't have an inherent/obvious order. This can be avoided by specifying the keywords but this makes the function call even longer. Imaginetranslate(a=a, b=b, c=c, ...)
with real variable names.
To resolve/avoid the above problem I started to use dictionaries to pass large numbers of variables between functions. Then I noticed that I could also use the dictionaries to return variables....
Using the above example:
def translate(dict_of_values):
// some code
dict_of_values['x'] = something
dict_of_values['y'] = something_else
dict_of_values['z'] = something_other
// and if I want to call the function I state:
some_dict['a'] = 1 // also populate values for b, c, d, ..., p
translate(some_dict)
My question is as follows:
- Does this coding pattern have a name?
- Will other programmers easily understand the format?
- What problems am I introducing that will bite me in the future?
- Is there a better alternative, assuming that I can't avoid functions that have a large number of mandatory variables?
I understand that I could be using **kwargs by writing defining the function as translate(**dict_of_values):
and then calling translate(**some_dict)
but I can't see any particular advantage to doing so. If anything, it would make the code slightly more verbose as I'd have to add return and assignment statements to achieve the same end point.