如何向函数的__code__传递参数?
下面的代码可以正常工作:
def spam():
print "spam"
exec(spam.__code__)
spam
但是如果 spam
需要参数呢?
def spam(eggs):
print "spam and", eggs
exec(spam.__code__)
TypeError: spam() 需要 1 个参数(但给了 0 个)
假设我只能访问一个代码对象,而不能直接访问这个函数,我该如何在执行这个代码对象时传递参数呢?使用 eval 可以做到吗?
补充说明:因为大多数读者可能不相信这个问题的实用性,下面是一个使用场景:
我想把一些小的 Python 函数保存到文件中,以便可以从其他电脑调用它们。(这里不需要多说,这种情况限制了可用的函数。)直接保存函数对象是行不通的,因为这样只会保存函数的名字和它所在的模块。相反,我可以保存函数的 __code__
。当我重新加载时,当然函数的引用就消失了,这就是我无法调用这个函数的原因。因为在运行时我根本没有这个函数。
另一个使用场景:
我在一个文件中有几个函数,它们用来计算一些数据并将结果存储到硬盘上。这些计算耗时很长,所以我不想每次都执行这些函数,只想在函数实现发生变化时才执行。
我有一个版本是针对整个模块运行的,而不是单个函数。它的工作原理是查看模块所在文件的修改时间。但如果我有很多函数,不想把它们分开到不同的文件中,这种方法就不适用了。
6 个回答
我觉得在你更大的应用程序中,可能有一些设计上的考虑,让你不必太在意这个问题。比如说,可能有一些“已知良好且有效”的函数集合,这些函数作为一个模块被分发,执行的代理程序都知道这些函数的存在。
话虽如此,有一个比较简单的解决办法是:
>>> 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
>>>
我完全反对这样使用__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__
。
你能把这个函数改成不接收任何参数吗?这样的话,变量就可以从本地或全局环境中查找,你可以把它们传给exec
:
>>> def spam():
... print "spam and", eggs
...
>>> exec(spam.__code__, {'eggs':'pasta'})
spam and pasta
(那为什么不直接把整个函数作为字符串发送呢?可以把"def spam(eggs): print 'spam and', eggs"
这个函数用Pickle处理,然后在另一边用exec
执行这个字符串(当然要先验证一下)。)