以下作品:
def spam():
print "spam"
exec(spam.__code__)
垃圾邮件
但是如果spam
接受参数呢?
def spam(eggs):
print "spam and", eggs
exec(spam.__code__)
TypeError:spam()只需1个参数(0给定)
鉴于,我无法访问函数本身,只能访问代码对象,如何在执行代码对象时将参数传递给代码对象?是否可以使用eval?
编辑:由于大多数读者往往不相信这有用,请参阅以下用例:
我想将小型Python函数保存到文件中,以便可以调用它们,例如从另一台电脑。 (这里不用说这个用例严格限制了可能的功能。)pickle函数对象本身不起作用,因为这只保存了定义函数的名称和模块。相反,我可以挑选函数的__code__
。当我再次取消它时,当然对函数的引用消失了,这就是我无法调用该函数的原因。我只是在运行时没有它。
另一个用例:
我在一个文件中处理几个函数,计算一些数据并将其存储在硬盘上。计算会耗费大量时间,因此我不希望每次都执行这些函数,但只有在函数的实现发生变化时才会执行。
我有一个版本的运行整个模块而不是一个函数。它通过查看实现模块的文件的修改时间来工作。但如果我有许多我不想在单个文件中分离的函数,那么这不是一个选项。
答案 0 :(得分:15)
我完全反对使用__code __。
虽然我是一个好奇的人,这是理论上可以做的事情:
code # This is your code object that you want to execute
def new_func(eggs): pass
new_func.__code__ = code
new_func('eggs')
同样,我永远不想看到这个用过。如果要在运行时加载代码,可能需要查看__import__
。
答案 1 :(得分:9)
您可以将功能更改为而不是采取任何参数吗?然后从locals / globals中查找变量,您可以将其提供给exec
:
>>> def spam():
... print "spam and", eggs
...
>>> exec(spam.__code__, {'eggs':'pasta'})
spam and pasta
(为什么不将整个函数作为字符串发送?Pickle "def spam(eggs): print 'spam and', eggs"
,exec
另一边的字符串(验证后)。)
答案 2 :(得分:6)
我认为在您的大型应用程序中可能存在一些设计注意事项,这些注意事项可能会使您不关心此问题,例如可能将一些“已知良好且有效”的函数集合作为执行代理知道的模块或某些内容进行分发。
那就是说,一个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
>>>
答案 3 :(得分:5)
代码对象是函数的一部分,因此上面的几个答案建议创建一个虚函数并用__code__
替换它codeObject
。这是避免制作和丢弃新__code__
:
import new
newFunction = new.function(codeObject, globals())
(在Python 2.7中测试,其中spam.__code__
被命名为spam.func_code
。)
答案 4 :(得分:1)
我认为您不能将参数传递给exec
或eval
,以便将它们传递给代码对象。
您可以使用exec / eval的字符串版本,例如exec("spam(3)")
。
您可以创建另一个绑定参数的代码对象,然后执行以下命令:
def spam_with_eggs():
return spam(3)
exec(spam_with_eggs.__code__)
(我认为你也可以用functools.partial
实现这个目标,但是没有让它发挥作用。)
编辑:
在阅读了您的其他解释之后,我想到了如何从代码对象重新建立正确的函数。这个简单的方法对我有用(在python2.5中):
def bar():pass
bar.func_code = spam.func_code
bar(3) # yields "spam and 3"
答案 5 :(得分:1)
我的方法,我觉得它更漂亮
def f(x):
print(x, x+1)
g = type(f)(f.__code__, globals(), "optional_name")
g(3)