5

Can someone think of an example with good practice that uses exec?

If there is always a more efficient and secure way to replace exec, why python doesn't deprecate exec?

zvisofer
  • 1,346
  • 18
  • 41
  • Go to related questions `Why should exec() and eval() be avoided?` or `26 In Python, why doesn't exec work in a function with a subfunction?` – Grijesh Chauhan Feb 04 '14 at 13:21
  • 2
    @GrijeshChauhan While there are a few questions explaining why `eval`/`exec` are generally a bad practice, there's no example of actual *good* practice, so in my opinion this is a valid question – loopbackbee Feb 04 '14 at 13:24
  • @goncalopp you are correct.... – Grijesh Chauhan Feb 04 '14 at 13:26
  • Just another example: I made a small "framework" that completely decoupled the dependencies of a module by mocking them, and thus allowing for testing the untestable. Ie, I was writing code on-the-fly that mostly behaved like the original one, but for some points. Without exec that could not be possible. – bgusach Feb 04 '14 at 15:50

2 Answers2

5

As explained in other questions, eval/exec are considered bad practice because they're generally abused to do a task where they aren't needed, leading to potential security issues and generally bad programming.

There are, however, valid uses for these mechanisms, and they expose important functionality that is not available elsewhere - executing arbitrary code at runtime.

Imagine, for example, that you want write a application that updates itself. You could fetch a script from a remote URL that runs with exec and updates your application to the latest version. While doing something like that, by itself, would pose a great security hazard, it's not hard to make the process secure through the use of digital signatures.

You can find another common use in the code module source: executing code input from the user at runtime for debugging purposes.

loopbackbee
  • 21,962
  • 10
  • 62
  • 97
3

No, eval and related tools are not always bad by any measure.

There are a number of things that only work well when they are expressed as regular functions with regular, positional or keyword arguments (not magic *args or **keywords args). There's no way to dynamically create a function with a desired set of arguments, except with eval.

For a good example of how this can be used, examine the implementation of collections.namedtuple. Although it would be possible to create a class factory like that without eval, but all of the functions it defines, __new__ and _replace in particular, would have useless help text, and would be a less convenient tool without it. Worse, the non-eval implementation would almost certainly be SLOWER.

Another, more sweeping example of this exact use of eval is the fine decorator library, which generalizes this practice in a collection of tools that allow you to dynamically create functions with particular function signatures; it uses eval internally.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 1
    Huh? You can dynamically create a function with `types.FunctionType` and passing in the code object. Of course, I guess when you `compile` the code object you are using exec behind the scenes. – wim Feb 04 '14 at 13:45
  • yes, `compile` and `types.CodeType` have all of the powers and shortcomings of `eval` and `exec`. If you're creating functions dynamically in this way, though, you probably should use `eval` in preference to creating the bytecode explicitly, since the python you'd have to eval is portable across implementations, but bytecode hacks generally are not. For instance, the signature of `types.CodeType` is implementation defined. – SingleNegationElimination Feb 04 '14 at 16:05
  • It's probably preferable to inherit `collections.Callable`, for all practical purposes a callable class is a function. I agree with the answer but I do question the correctness of this statement "There's no way to dynamically create a function with a desired set of arguments, except with eval." – wim Feb 04 '14 at 16:25
  • @wim: I'm interested in a counterexample. specifically can you show me an `x`, which satisfies `inspect.getargspec(x(y)) == inspect.getargspec(eval('lambda {0}: ({0})'.format(', '.join(y))))` where `y` is a list of strings (eg `y = ['foo', 'bar', 'baz']`? – SingleNegationElimination Feb 04 '14 at 16:46