0

I need to assign a numeric value, which is returned from a function, to a variable name by using exec() command:

def func1(x,y):
    return x+y

def main(x,y,n):
    x=3; y=5; n=1
    t = exec("func%s(%s,%s)" % (n,x,y))
    return t**2

main(3,5,1)

I have many functions like "func1", "func2" and so on... I try to return t = func1(x,y) with theexec("func%s(%s,%s)" % (n,x,y)) statement. However, I cannot assign a value, returned fromexec().

There is a partly similar question on SE, but it is written for Python3 and is also not applicable to my case.

How can we resolve this problem or is there a more elegant way to perform such an operation, maybe without the use of'exec()'?

By the way, as "func%s(%s,%s)" % (n,x,y) is a statement, I used exec. Or should I better use eval?

Community
  • 1
  • 1
T-800
  • 1,543
  • 2
  • 17
  • 26
  • Why are you doing any of this? It seems a really strange design. – Gareth McCaughan Mar 02 '14 at 23:27
  • More specifically: why have all these functions and then refer to them by name, rather than e.g. having them in a data structure of some kind? (e.g., if they are all the sort of thing you can put into a lambda, a dict whose values are lambdas?). – Gareth McCaughan Mar 02 '14 at 23:28
  • Recommendations about other possible ways are also very welcome! :) – T-800 Mar 02 '14 at 23:28
  • Also: Why do you say that "func(...)" is a statement? It looks like an expression to me. If you have to do things this way, then yes, you want eval rather than exec -- but, again, why? – Gareth McCaughan Mar 02 '14 at 23:29
  • It would be useful to have more context. What are all these functions? Why are there so many? Why are you referring to them by name like this? If the details are confidential, I'm sure you can be strategically vague or make up a close-enough cover story... – Gareth McCaughan Mar 02 '14 at 23:29
  • I will think about the implementation of your proposed way, but that would probably be quite difficult because, those functions (func1 in my example above) call other functions, which is quite different from each other... But thanks for the great idea, that would be really a neat way and I will try to do that. – T-800 Mar 02 '14 at 23:34
  • In that case, indeed that might not be a good design. Again, with more information about what you're actually trying to achieve it's probably possible to make better recommendations. For instance, are you basically making your own little programming language (or, at a lower level, a virtual machine)? If so, it might be better to actually make one, putting in a bit more infrastructure now for cleaner code later. – Gareth McCaughan Mar 02 '14 at 23:36
  • Actually, I am not clear with whether `func%s(%s,%s)" % (n,x,y)` is a statement or an expression. I thought it was a statement... – T-800 Mar 02 '14 at 23:37
  • It is not that much hard stuff; it is just a numeric solution algorithm. It is not confidential but, even if I copy+paste some of them here, it would be really long... – T-800 Mar 02 '14 at 23:40
  • I wasn't suggesting copying-and-pasting anything! But more information would be nice -- "a numeric solution algorithm" could mean so many different things. Are we talking e.g. about different algorithms for solving differential equations (Runge-Kutta of different degrees, assorted predictor-corrector schemes, etc.), or something like that? I'm having trouble why you'd need a very large number of functions with such similar interfaces. – Gareth McCaughan Mar 03 '14 at 00:06
  • Another obvious candidate design: make a bunch of classes, each with a method of the same name that does whatever this thing is, and then what you pass to functions like your `main` above is the class, or an instance of that class. So, e.g., you might have a class `ODESolver` with a method `solve` and subclasses with names like `RungeKuttaODESolver`, each subclass having its own `solve` method, and then you'd call `main(RungeKuttaODESolver,3,4)` or whatever. – Gareth McCaughan Mar 03 '14 at 00:07
  • In fact, that approach is near enough to the canonical way to do this sort of thing in a language that supports it that I'm going to go ahead and make an answer saying so. Of course it may turn out that it doesn't meet your specific needs, in which case knowing those needs will probably make it possible to come up with a better solution. – Gareth McCaughan Mar 03 '14 at 00:12

1 Answers1

0

It is almost always a really bad idea to get at functions and variables using their names as strings (or bits of their names as integers, as in the example code in the question). One reason why is that eval or exec can do literally anything and you generally want to avoid using code constructs whose behaviour is so hard to predict and reason about.

So here are two ways to get similar results with less pain.

First: Instead of passing around magic index numbers, like the 1 in the code above, pass the actual function which is, itself, a perfectly reasonable value for a variable in Python.

def main(x,y,f):
  return f(x,y)**2

main(3, 5, func1)

(Incidentally, the definition of main in the question throws away the values of x,y,n that are passed in to it. That's probably a mistake.)

Second: Instead of making these mere functions, make them methods on classes, and pass around not the functions but either the classes themselves or instances of the classes.

class Solver:
  def solve(self, x,y): return "eeeek, not implemented"

class Solver1:
  def solve(self, x,y): return x+y

def main(x, y, obj):
  return obj.solve(x,y)**2

main(3, 5, Solver1())

Which of these is the better approach depends on the details of your application. For instance, if you actually have multiple "parallel" sets of functions -- as well as your func1, func2, etc., there are also otherfunc1, otherfunc2 etc. -- then this is crying out for an object-oriented solution (the second approach above).

In general I would argue for the second approach; it tends to lead to cleaner code as your requirements grow.

Gareth McCaughan
  • 19,888
  • 1
  • 41
  • 62
  • Second approach helped me a lot. I changed my code appropriately and now, I do not need to make such a definition. Thanks a lot! – T-800 Mar 04 '14 at 10:43