Python:如何将参数传递给函数的__code__?

时间:2022-12-07 23:07:43

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)

TypeError:spam()只取1个参数(给定0)

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?

鉴于,我无法访问函数本身,只能访问代码对象,如何在执行代码对象时将参数传递给代码对象?是否可以使用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.

我想将小Python函数保存到文件中,以便可以调用它们,例如从另一台电脑。 (这里不用说这个用例严格限制了可能的功能。)pickle函数对象本身不起作用,因为这只保存名称和定义函数的模块。相反,我可以挑选函数的__code__。当我再次取消它时,当然对函数的引用消失了,这就是我无法调用函数的原因。我只是在运行时没有它。

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.

我有一个版本的运行整个模块而不是一个功能。它通过查看实现模块的文件的修改时间来工作。但如果我有许多我不想在单个文件中分离的函数,那么这不是一个选项。

6 个解决方案

#1


9  

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:

你能改变这个功能不参加任何争论吗?然后从locals / globals中查找变量,您可以在其中提供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.)

(为什么不将整个函数作为字符串发送?Pickle“def spam(eggs):打印'spam and',eggs”,并在另一端执行字符串(验证后)。)

#2


15  

I am completely against this use of __code__.

我完全反对__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.

再一次,我永远不想看到这种用过。如果要在运行时加载代码,可能需要查看__import__。

#3


6  

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:

也就是说,一个hacky解决方案是:

>>> 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
>>> 

#4


5  

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__:

代码对象是函数的一部分,因此上面的几个答案建议创建一个虚函数并用你的codeObject替换它的__code__。这是避免制作和丢弃新__code__的另一种方法:

import new
newFunction = new.function(codeObject, globals())

(Tested in Python 2.7, where spam.__code__ is named spam.func_code.)

(在Python 2.7中测试,其中spam .__ code__被命名为spam.func_code。)

#5


1  

I don't think you can pass arguments to either exec or eval, so that they are passed to the code object.

我不认为你可以将参数传递给exec或eval,以便将它们传递给代码对象。

You could resort to the string version of exec/eval, e.g. exec("spam(3)").

您可以使用exec / eval的字符串版本,例如EXEC( “垃圾邮件(3)”)。

You could create another code object that binds the argument, and then exec this:

您可以创建另一个绑定参数的代码对象,然后执行以下操作:

def spam_with_eggs():
   return spam(3)
exec(spam_with_eggs.__code__)

(I thought you could also achieve this with functools.partial, but didn't get it to work).

(我以为你也可以用functools.partial来实现这一点,但是没有让它工作)。

EDIT:

编辑:

After reading your additional explanations I thought of ways to re-establish a proper function from the code object. This simple approach worked for me (in python2.5):

在阅读了您的其他解释之后,我想到了从代码对象重新建立正确函数的方法。这个简单的方法对我有用(在python2.5中):

def bar():pass
bar.func_code = spam.func_code
bar(3)  # yields "spam and 3"

#6


1  

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)

#1


9  

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:

你能改变这个功能不参加任何争论吗?然后从locals / globals中查找变量,您可以在其中提供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.)

(为什么不将整个函数作为字符串发送?Pickle“def spam(eggs):打印'spam and',eggs”,并在另一端执行字符串(验证后)。)

#2


15  

I am completely against this use of __code__.

我完全反对__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.

再一次,我永远不想看到这种用过。如果要在运行时加载代码,可能需要查看__import__。

#3


6  

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:

也就是说,一个hacky解决方案是:

>>> 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
>>> 

#4


5  

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__:

代码对象是函数的一部分,因此上面的几个答案建议创建一个虚函数并用你的codeObject替换它的__code__。这是避免制作和丢弃新__code__的另一种方法:

import new
newFunction = new.function(codeObject, globals())

(Tested in Python 2.7, where spam.__code__ is named spam.func_code.)

(在Python 2.7中测试,其中spam .__ code__被命名为spam.func_code。)

#5


1  

I don't think you can pass arguments to either exec or eval, so that they are passed to the code object.

我不认为你可以将参数传递给exec或eval,以便将它们传递给代码对象。

You could resort to the string version of exec/eval, e.g. exec("spam(3)").

您可以使用exec / eval的字符串版本,例如EXEC( “垃圾邮件(3)”)。

You could create another code object that binds the argument, and then exec this:

您可以创建另一个绑定参数的代码对象,然后执行以下操作:

def spam_with_eggs():
   return spam(3)
exec(spam_with_eggs.__code__)

(I thought you could also achieve this with functools.partial, but didn't get it to work).

(我以为你也可以用functools.partial来实现这一点,但是没有让它工作)。

EDIT:

编辑:

After reading your additional explanations I thought of ways to re-establish a proper function from the code object. This simple approach worked for me (in python2.5):

在阅读了您的其他解释之后,我想到了从代码对象重新建立正确函数的方法。这个简单的方法对我有用(在python2.5中):

def bar():pass
bar.func_code = spam.func_code
bar(3)  # yields "spam and 3"

#6


1  

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)