1
code = "def foo(): return 'bar'" def lol(code): exec code return foo a = lol(code) print a() 

This works normally, but the problem starts when we don't know what the function in the string is called. If I can guarantee that the code will be small, with a single function, how can I return that function?

One solution I thought of was just requiring the function be called 'foo' etc, so I can just return that, but it feels ugly.

Thoughts?

2
  • Using exec for dynamic code generation is generally frowned upon. I would redesign the code in a way that it does not need exec. Commented May 7, 2016 at 13:15
  • I can't think of another way to evaluate a string into Python code. Commented May 7, 2016 at 13:16

1 Answer 1

1

You could do it by explicitly specifying dictionaries exec should use for the global and local execution context. Afterwards the one used for locals should have a single entry for the function object, which can be returned without knowing its name since it should be the only item defined in the dictionary:

from textwrap import dedent import types def lol(code): globals_ = {"__builtins__": None} # no built-ins for safety locals_ = {} exec(code, globals_, locals_) if len(locals_) != 1: raise ValueError("code didn't define exactly one item") value = locals_.popitem()[1] # get value of the one item defined if type(value) != types.FunctionType: raise ValueError("code didn't define a function") return value # return function object that was defined my_code = dedent(""" def foo(): return 'bar' """) a = lol(my_code) print(a()) 
Sign up to request clarification or add additional context in comments.

4 Comments

Should this have the same output on both Python verisons?
You'd have to change the last line to print(a()) because print is a function in Python 3, not a statement, but otherwise it works the same in both versions. I intentionally used the tuple form of exec because it provides compatibility with Python 3.
Do you know any way I could handle if the string of code contained more than one function?
In that case you'd need some way of telling them apart, especially because they'll be in random order in the locals_ dictionary after the exec. Just requiring the function(s) of interest to have some predefined name(s) would probably be the best approach (and is a fairly common plug-in architecture).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.