I'm looking for a function that will let me execute code passed as a string, but also return a value upon completion. I have found Python's exec
and eval
, each of which manage to do a part of what I want:
exec
lets me execute some lines of code which I pass as a string: print to the console; set or change variables; write to files etc.eval
lets me evaluate a single expression and returns the value of this expression.
However, the functionality I want is to combine these: with a single function call, I want to execute some arbitrary code, and then return a value, which might be dependent on the code executed.
To contextualise, I want to modify the in-built Pickle __reduce__
method so that I can execute some code in the background while the object un-pickles. However, at the end of that code execution, I still want to return the original object that was pickled.
Pickle's __reduce__
has to return a function which is used to reassemble the object on un-pickling, so I want a use of eval
and exec
that lets me combine their usage into a single function call.
As an example, my code might look something like this:
def __reduce__(self):
code = """with open("flag.txt", "w") as f:\n\tf.write("A flag I have left!")\ndict()"""
return exec, (code, ), None, None, iter(self.items())
The odd return formatting is a quirk of Pickle. The oddly formatted code string should do this:
with open("flag.txt", "w") as f:
f.write("A flag I have left")
dict() # I'm trying to get the intepreter to 'evaluate' this final line
However, this doesn't work, as exec
just does nothing with this final line, and returns None
. If I swap, and use eval
instead, then I get an error too, as eval
can't do anything with the lines above.
I ave tried using the in-built compile
method, but this doesn't actually seem to help because eval
still won't evaluate compiled execution code.
I also see that this problem has popped up elsewhere on SO (here and here) but I'm unsatisfied with the answers provided, because they involve defining new functions, which are then useless in the context of getting Pickle to execute them on un-pickling, where the interpreter is naive of their definition.
Is there any way to neatly combine these expressions to achieve arbitrary execution as well as returning a value?