2

I want to be able to take a string which describes a Python function and turn it into a function object which I can then call. For example,

myString = "def add5(x):
   return x + 5"
myFunc = myString.toFunction() <-- something like this?
print myFunc(10)     <-- should print 15

My desire to be able to do this arose from a problem posed in my theoretical foundations of computing class, which operates under an assumption of SISO (String in, String out). In particular, we are examining the uncomputable problem yesOnString(P,I), which returns "yes" if P(I) = "yes" and "no" otherwise. Thus I want to be able to have a function P passed in String form as a parameter, and then have the function convert the string into a function which it then calls.

  • 1
    @Kingsley `eval()` wouldn't work but `exec()` would but it would just introduce `add5` as the function name. @SufiyanGhori you can't use `literal_eval` that is only for literals - and this is code. – AChampion Jan 31 '19 at 04:11
  • @AChampion - I think `exec()` is what the OP wants. Even if it supports `exec('import os')`, `exec('os.system("rm -rf blah")')`. – Kingsley Jan 31 '19 at 04:16
  • Yes, the obligatory warnings. – AChampion Jan 31 '19 at 04:18
  • @TigerhawkT3: This is not a duplicate. OP has clearly said he want to convert string to function and store it as a varialbe. This is not answered in the origianl question and answer. – Rahul Jan 31 '19 at 04:59
  • followup question: https://stackoverflow.com/questions/54453678/right-way-to-turn-an-input-string-into-a-callable-function-and-store-it-as-varia – Rahul Jan 31 '19 at 05:15
  • @Rahul - Yes it is a duplicate. The way to convert a string representing a function into a function is with either `exec` (to execute statements like `def`) or `eval` (to evaluate an expression like `lambda`). The `myFunc = myString.toFunction()` line just needs to be changed to `exec(myString)`, and then `add5` will be available in the namespace. It's the same thing, and that's how it's done. `myFunc = add5` is optional after that if you want to give the function a different name. Definitely a duplicate; no need to reopen. – TigerhawkT3 Jan 31 '19 at 20:08
  • @TigerhawkT3: What if the string is dynamically generated? How would you know the name of the function added to namespace for calling later. He asked for the specific implementation for converting a string to function and not add the string to a namespace. Your way will not solve the purpose of SO. every question will be duplicate. see my other answer if you don't understand https://stackoverflow.com/questions/54453678/right-way-to-turn-an-input-string-into-a-callable-function-and-store-it-as-varia – Rahul Feb 01 '19 at 05:21
  • @Rahul - If it's dynamically generated, maybe it should be a lambda function so it can be an expression evaluated with `eval` and assigned to the chosen name. That also demonstrates why this sort of thing is a bad idea. However, the point stands that the functions to execute or evaluate strings of Python code - which is what this is - are `exec` and `eval`, as described in the duplicate. There's nothing new and exciting about it this old and ill-advised notion. – TigerhawkT3 Feb 01 '19 at 22:01
  • How can you assume that if its dynamically generated, it should be a lambda function. OP has clearly mentioned a function with def keyword. – Rahul Feb 02 '19 at 04:29
  • @TigerhawkT3: Please see my followup question in previous comment and you will understand. – Rahul Feb 02 '19 at 04:30
  • @Rahul - I assume that the string will be a lambda function at the very least because to do otherwise would be a giant anti-pattern and a very poor idea. Given that functions are first-class objects anyway, it's much easier to just use a factory to create the function you're interested in without messing with arbitrary string execution. – TigerhawkT3 Feb 02 '19 at 06:09
  • Based on your utter assumption you closed the question? – Rahul Feb 02 '19 at 06:10
  • @TigerhawkT3 the answers to the question which you marked this as a duplicate of did not answer my question. I was already aware of the exec and eval commands but as Rahul has pointed out these simply add the new function to the namespace. In that case I would have to add regex to identify the function name from the input string which is a bit ugly, and even if that is truly the only way I think that would be enough of a difference to warrant this being a separate question. – Noah Hunt-Isaak Feb 02 '19 at 17:07
  • @Rahul I don't have the reputation to upvote comments but I appreciate you fighting on my behalf! :) – Noah Hunt-Isaak Feb 02 '19 at 17:12
  • `eval` doesn't add anything to a namespace. It just evaluates a string representing a Python expression. For example, `myString = 'lambda x: x+5'` and then `myFunc = eval(myString)`. There is no function or method to read a string with a `def` statement, grab the function object that would be created by such code, and return it to the caller. You shouldn't be creating such strings in the first place. Use a factory function or something instead. This site is intended to solve problems, not create them. – TigerhawkT3 Feb 03 '19 at 00:19
  • @TigerhawkT3 "There is no function or method to read a string with a def statement, grab the function object that would be created by such code, and return it to the caller" as per your statement, and OP asked that question and you marked it as a duplicate. Wonderful. – Rahul Feb 04 '19 at 04:23
  • @Rahul - Answering that [XY Problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem) anti-pattern would also be too broad for a question. The right way of turning a string into a function is answered in the duplicate. I'm afraid that's all the time I can donate to this issue. – TigerhawkT3 Feb 04 '19 at 08:37
  • @TigerhawkT3: I didn't know about this XY phenomenon. Thanks for pointing out. Let's close this issue. No matter marked duplicate or closed, answering this question is an anti-pattern. that's all. Thanks. – Rahul Feb 04 '19 at 10:21

1 Answers1

-1

This is possible with the Python built-in exec() function.

myString = "def myFunc(x): return x + 5"
exec( myString )  # myFunc = myString.toFunction() <-- something like this?
print( myFunc(10) )  #   <-- should print 15

If you want to keep the same naming pattern

myString = "def add5(x): return x + 5"
exec( myString )  # myFunc = myString.toFunction() <-- something like this?
myFunc = add5
print( myFunc(10) )  #   <-- should print 15

In terms of safety: exec() executes the given string, any given string.

import os.system
os.system("format C:")  # etc.

So be really careful how it's used. Certainly not on any sort of user's input.

Kingsley
  • 14,398
  • 5
  • 31
  • 53