How to pass arguments to the __code__ of a function?
Solution 1
Can you change the function to not take any arguments? The variables is then looked up from the locals/globals where you can supply into exec
:
>>> def spam():
... print "spam and", eggs
...
>>> exec(spam.__code__, {'eggs':'pasta'})
spam and pasta
(Why not just send the whole function as a string? Pickle "def spam(eggs): print 'spam and', eggs"
, and exec
the string (after verification) on the other side.)
Solution 2
I am completely against this use of __code__.
Although I am a curious person, and this is what someone theoretically could do:
code # This is your code object that you want to execute
def new_func(eggs): pass
new_func.__code__ = code
new_func('eggs')
Again, I never want to see this used, ever. You might want to look into __import__
if you want to load code during run-time.
Solution 3
I think there are probably some design considerations in your larger application that could make you not care about this problem, like perhaps having some collection of 'known good and valid' functions distributed as a module that the executing agents know about or something.
That said, one hacky solution would be:
>>> def spam(eggs):
... print "spam and %s" % eggs
...
...
>>> spam('bacon')
spam and bacon
>>> def util():
... pass
...
...
>>> util.__code__ = spam.__code__
>>> util('bacon')
spam and bacon
>>>
Solution 4
A code object is part of a function, so several answers above suggest creating a dummy function and replacing its __code__
with your codeObject
. Here's another way that avoids making and throwing away a new __code__
:
import new
newFunction = new.function(codeObject, globals())
(Tested in Python 2.7, where spam.__code__
is named spam.func_code
.)
Solution 5
My method, I thing it`s more beautiful
def f(x):
print(x, x+1)
g = type(f)(f.__code__, globals(), "optional_name")
g(3)
Turion
Updated on June 28, 2022Comments
-
Turion almost 2 years
The following works:
def spam(): print "spam" exec(spam.__code__)
spam
But what if
spam
takes arguments?def spam(eggs): print "spam and", eggs exec(spam.__code__)
TypeError: spam() takes exactly 1 argument (0 given)
Given, that I don't have access to the function itself but only to a code object, how can I pass arguments to the code object when executing it? Is it possible with eval?
Edit: Since most readers tend not to believe in the usefulness of this, see the following use case:
I want to save small Python functions to a file so that they can be called e.g. from another computer. (Needless to say here that this usecase restricts the possible functions severely.) Pickling the function object itself can't work because this only saves the name and the module where the function is defined. Instead, I could pickle the
__code__
of the function. When I unpickle it again, of course the reference to the function vanished, which is why I can't call the function. I simply don't have it at runtime.Another usecase:
I work on several functions in one file that calculate some data and store it on the hard drive. The calculations consume a lot of time so I don't want to execute the functions every time, but only when the implementation of the function changed.
I have a version of this running for a whole module instead of a function. It works by looking at the modification time of the file where the module is implemented in. But this is not an option if I have many functions that I don't want to separate in single files.
-
Admin about 13 yearsJust call the function, period, full stop.
-
Turion about 13 yearsOf course I would do that in this simple example case. I'm not so stupid not to see this. But what if all I have is the code object itself?
-
Admin about 13 yearsThen you have a more serious problem, I'd say. You rarely (really rarely) need to fiddle with stuff from this level of abstraction, and by default I doubt you're in a situation where this is the case, so I suggest you make sure you get a function instead of a code object.
-
user1066101 about 13 years@Turion: What is the distinction between a function and the code object itself? Where did you get this code object from? Why isn't it just a function?
-
Turion about 13 yearsSee my edit to the question for clarification and a possible usecase. @delnan If there is a possibility to solve my above mentioned pickling problem without exec or eval, I would be happy to do so.
-
Admin about 13 yearsThere must be an easier way. It's impossible to think about details without knowing what exactly the functions do, but it should be quite possible to serialize only a bit of data needed to reconstruct the function (e.g.
lambda x: 10 < x < 20
can be reduced to the upper and lower bound). Also see stackoverflow.com/questions/1253528/… if that's absolutely not an option. -
Y.H Wong about 13 yearsSo you want to send the pickled function bytecodes across the wire and you want the client to be able to just allow code execution arbitrarily from some random location? Whoa. This is so dangerous in so many ways... What you want is some form of RPC. Don't cut corners.
-
XORcist about 13 years@Turion: the proper way to distribute code is with a python package.
-
user1066101 about 13 yearsWhat's wrong with simply sending the function's source back and forth?
-
Turion about 13 yearsSee my second, more realistic usecase. @Y.H. Wong, möter: You are right, this is a serious security hole and therefore not a realistic usecase. @S. Lott: Good idea, as could be done with the inspect module. But I fear this doesn't work if the function is defined dynamically.
-
user1066101 about 13 years@Turion: "the function is defined dynamically"? Without source? You mean a
lambda
? -
Turion about 13 yearsFor example a definition in the body of another function. But I agree that this might be uncommon enough to forget about it.
-
-
Turion about 13 yearsI like this solution, too, but unfortunately I can only tick one of the solutions, I think. But I agree, it's really hacky.
-
Turion about 13 yearsI like this, like Gustav Larssons solution.
-
kindall about 13 yearsYou can also construct a function using the function type. e.g.
new_func = type(lambda: 0)(code, globals())
This is a little less hacky. You could then write a function to construct a wrapper function from a code object and call the resulting function. -
Turion about 13 yearsThat's an improvement. To increase the readability of your solution, I would recommend using
types.FunctionType
instead oftype(lambda: 0)
. -
Turion almost 13 yearsThis does not significantly differ from some other solutions.
-
kxr over 8 yearsThis should be tagged as most right answer to the point, though a comment in the other answer using still that odd hack mentions the same via
types.FunctionType
(place and idea well hidden for new readers). Yet referrals to other answers should be removed / not be on top; and the example should be complete enough likenew.function(spam_code_object, globals())("some eggs")
. (Python 2.7 and 2.6 also supportfunc.__code__
besidesfunc.func_code
) -
Hack5 almost 5 yearsCombine this with stackoverflow.com/a/33112180/5509575 and I think you have a fully working answer, although I couldn't get the linked answer to do anything
-
aliqandil almost 5 yearsThis is quite interesting, Just to be more precise, you can also provide the default arguments just in case. Add this as a keyword argument to the constructor
argdefs = f.__defaults__