Overview
At some point at run-time, I want to create a function that exactly takes a given number of arguments (known only at run-time). Exactly here means that this must not be a variadic function. Is there any way to do this without resorting to eval
or similar ways to interpret strings as code?
My problem (slightly reduced)
I want to create a function that takes its arguments and passes them to another function as an iterable. Usually, I could do this as follows:
my_function = lambda *args: other_function(args)
Unfortunately, my_function
will be called by some routine that cannot properly handle variadic functions¹. However, my_function
will always be called with the same number of arguments n_args
. So, if I knew n_args
to be 3, I could use:
my_function = lambda a,b,c: other_function((a,b,c))
The problem is that I only get to know n_args
at run-time, just before creating my_function
. Thus, I need to generalise the above.
What I found so far
I achieve what I want using
eval
(orexec
or similar):arg_string = ",".join( "arg_%i"%i for i in range(n_args) ) my_function = eval( "lambda %s: other_function((%s))" % (arg_string,arg_string), {"other_function":other_function} )
The downside to this is that I have to use
eval
, which is ugly and bad. If you so wish, my question is how to create something equivalent to the above without usingeval
or obtaining a variadic function.SymPy’s
lambdify
allows me to dynamically create functions with a fixed number of arguments at run-time (that work in my context), but looking at the source code, it seems that it useseval
under the hood as well.
¹ It’s a compiled routine created with F2Py. I cannot change this with reasonable effort right now. Yes, it’s sad and on the long run, I will find try to fix this or get this fixed, but for now let’s accept this as given.