6

I try:

def test(w,sli): s = "'{0}'{1}".format(w,sli) exec(s) return s print test("TEST12344","[:2]") 

its return 'TEST12344'[:2]

How to return value from exec in function

3 Answers 3

19

Think of running the following code.

code = """ def func(): print("std out") return "expr out" func() """ 

On Python Console

If you run func() on the python console, the output would be something like:

>>> def func(): ... print("std out") ... return "expr out" ... >>> func() std out 'expr out' 

With exec

>>> exec(code) std out >>> print(exec(code)) std out None 

As you can see, the return is None.

With eval

>>> eval(code) 

will produce Error.

So I Made My exec_with_return()

import ast import copy def convertExpr2Expression(Expr): Expr.lineno = 0 Expr.col_offset = 0 result = ast.Expression(Expr.value, lineno=0, col_offset = 0) return result def exec_with_return(code): code_ast = ast.parse(code) init_ast = copy.deepcopy(code_ast) init_ast.body = code_ast.body[:-1] last_ast = copy.deepcopy(code_ast) last_ast.body = code_ast.body[-1:] exec(compile(init_ast, "<ast>", "exec"), globals()) if type(last_ast.body[0]) == ast.Expr: return eval(compile(convertExpr2Expression(last_ast.body[0]), "<ast>", "eval"),globals()) else: exec(compile(last_ast, "<ast>", "exec"),globals()) exec_with_return(code) 
Sign up to request clarification or add additional context in comments.

5 Comments

Wow, this is the only place I've seen this problem I've been having with None begin returned from exec command and what to do about it. Your code worked as a drop-in. Added your code, changed 1 line of my code, and it works!
I've been creating a mock backend server for testing the frontend, and I wanted to allow arbitrary Python expressions to be executed on the server. This has been extraordinarily handy — offering the familiar eval semantics of the IPython shell from my HTTP API. Thank you!
The idea is great here and it was exactly what I needed to implement some behaviour similar to how the Python console works. However, I wonder if the implementation makes it look more complicated than it needs to be. Is there any technical reason for needing the two copies? Why not simply pop the node off code_ast.body if it is an Expr? Then, either way, code_ast can simply be exec'ed as is. Finally, if we did pop off the last node it can be converted to an Expression as above and eval'ed.
Clever, but it doesn't always do what you might expect. With the following input 'if True:\n "hello"\nelse:\n "world"' the output is neither "hello", nor "world", but None.
Great! But, if called from function, it leaks and got outside (maybe because you use globals). def foo(): exec_with_return(code) # exec(code) func() foo() func()
5

exec() doesn't just evaluate expressions, it executes code. You would have to save a reference within the exec() call.

def test(w, sli): exec('s = "{}"{}'.format(w, sli)) return s 

If you just want to evaluate an expression, use eval(), and save a reference to the returned value:

def test(w,sli): s = "'{0}'{1}".format(w,sli) s = eval(s) return s 

However, I would recommend avoiding exec() and eval() in any real code whenever possible. If you use it, make sure you have a very good reason to do so.

3 Comments

This does not work in python 3, giving a NameError for s
@Eric As you can see by the OP's use of print as a statement rather than a function, Python 3 is not being used here.
You're right, but I and other users stumbling across this answer are increasingly more likely to be using python 3 - so I left a note to save them time trying it.
4

My findings in Python 3.8 in 2020

Eval Logic:

a = eval("1 + 99") print(a) # Output: 100 

Exec Logic:

exec("a = 1 + 99") print(a) # Output: 100 

So exec executes in the current scope.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.