60

For testing purposes I want to directly execute a function defined inside of another function.

I can get to the code object of the child function, through the code (func_code) of the parent function, but when I exec it, i get no return value.

Is there a way to get the return value from the exec'ed code?

4
  • I don't think you can do this with exec. You'll need to do something like georg's answer or use new as described in this answer. Commented May 28, 2014 at 17:27
  • @DavidMoles: new is deprecated, but types are fine, thanks. Commented May 28, 2014 at 17:34
  • Use eval, as @ex10se pointed out. Commented Dec 4, 2023 at 20:18
  • Well, very old, but the answer is here: stackoverflow.com/questions/3906232/… Commented Sep 7, 2024 at 4:05

11 Answers 11

48

A few years later, but the following snippet helped me:

the_code = '''
a = 1
b = 2
return_me = a + b
'''

loc = {}
exec(the_code, globals(), loc)
return_workaround = loc['return_me']
print(return_workaround)  # 3

exec() doesn't return anything itself, but you can pass a dict which has all the local variables stored in it after execution. By accessing it you have a something like a return.

I hope it helps someone.

Sign up to request clarification or add additional context in comments.

3 Comments

This is good. But you could just use this code and not have a seperate dictionary for "loc": exec(the_code) return_workaround = locals()['return_me']
This works, but inside the code I am unable to reference to variables that where defined outside it.
@bomben I didn't test it, but can't you pass your outer variables? It should be mentioned in the docs of exec(). :)
43

Yes, you need to have the assignment within the exec statement:

>>> def foo():
...     return 5
...
>>> exec("a = foo()")
>>> a
5

This probably isn't relevant for your case since its being used in controlled testing, but be careful with using exec with user defined input.

8 Comments

That is so weird, Especially that you dont need to declare the variable before hand.
This isn't working for me. exec('ds_id = kim_processors.%s.process(%s)' % (function.python_module, model_id)) does populate ds_id, as I can see in the Django locals debug output. However I then run cursor.execute("""select e.id as ... where dataset_id=%s""", (ds_id)) and get error "Exception Type: NameError Exception Value: name 'ds_id' is not defined". Yet locals shows ds_id is indeed set (to 14). Is there some restriction on its scope?
@Chris, I'm not sure what the issue is, but it sounds like a good question for the site. Try posting it separately as a question and refer here to show what you've tried.
Thanks @wnnmaw that's exactly what I did! Sorry forgot to follow up on this thread. The question and answers are here There is a better way of importing (importlib) and the duplicate question describes the scope issue beautifully. Thanks for responding.
This doesn't work, exec needs to be launched with globals, exec("a = foo()", globals())
|
16

use eval() instead of exec(), it returns result

1 Comment

This doesn't support stuff like imports though.
11

While this is the ugliest beast ever seen by mankind, this is how you can do it by using a global variable inside your exec call:

def my_exec(code):
    exec('global i; i = %s' % code)
    global i
    return i

This is misusing global variables to get your data across the border.

>>> my_exec('1 + 2')
3

Needless to say that you should never allow any user inputs for the input of this function in there, as it poses an extreme security risk.

1 Comment

Thank you! +1. I struggled a lot with getting a reference to a module given a string and this is what works. You can use this by giving the string as parameter code and it will return the actual module.
5

Something like this can work:

def outer():
    def inner(i):
        return i + 10


for f in outer.func_code.co_consts:
    if getattr(f, 'co_name', None) == 'inner':

        inner = type(outer)(f, globals())

        # can also use `types` module for readability:
        # inner = types.FunctionType(f, globals())

        print inner(42) # 52

The idea is to extract the code object from the inner function and create a new function based on it.

Additional work is required when an inner function can contain free variables. You'll have to extract them as well and pass to the function constructor in the last argument (closure).

Comments

4

This doesn't get the return value per say, but you can provide an empty dictionary when calling exec to retrieve any variables defined in the code.

# Python 3
ex_locals = {}
exec("a = 'Hello world!'", None, ex_locals)
print(ex_locals['a'])
# Output: Hello world!

From the Python 3 documentation on exec:

The default locals act as described for function locals() below: modifications to the default locals dictionary should not be attempted. Pass an explicit locals dictionary if you need to see effects of the code on locals after function exec() returns.

For more information, see How does exec work with locals?

3 Comments

This solution is far more simple and understandable than any other. Great Job :+1:
This is quite a duplicate of the answer above above by @Mr. B. in 2020.
@bogec You're right, this is essentially a simplified version of Mr. B's answer with an extra citation of Python's documentation. I can't remember if I referenced their post when I wrote this 4 years ago.
3

Here's a way to return a value from exec'd code:

def exec_and_return(expression):
    exec(f"""locals()['temp'] = {expression}""")
    return locals()['temp']

I'd advise you to give an example of the problem you're trying to solve. Because I would only ever use this as a last resort.

1 Comment

or: return eval(expression)
1

Here's a solution with a simple code:

# -*- coding: utf-8 -*-
import math

x = [0]
exec("x[0] = 3*2")
print(x[0]) # 6

2 Comments

Similar answers are already there posted. Better to look at new questions to answer where community needs you.
@Ank You are so right. But, I also want to share a simple method. Thank you.
1

Since Python 3.7, dictionary are ordered. So you no longer need to agree on a name, you can just say "last item that got created":

>>> d = {}
>>> exec("def addone(i): return i + 1", d, d)
>>> list(d)
['__builtins__', 'addone']
>>> thefunction = d[list(d)[-1]]
>>> thefunction
<function addone at 0x7fd03123fe50>

Comments

-1

if we need a function that is in a file in another directory, eg
we need the function1 in file my_py_file.py
located in /home/.../another_directory
we can use the following code:

def cl_import_function(a_func,py_file,in_Dir):
... import sys
... sys.path.insert(0, in_Dir)
... ax='from %s import %s'%(py_file,a_func)
... loc={}
... exec(ax, globals(), loc)
... getFx = loc[afunc]
... return getFx

test = cl_import_function('function1',r'my_py_file',r'/home/.../another_directory/')

test()
(a simple way for newbies...)

1 Comment

Whilst your answer may be useful, the question was asked 6 years ago and already has 5 answers, although none have been accepted.
-2
program = 'a = 5\nb=10\nprint("Sum =", a + b)'

program = exec(program)

print(program)

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.