如何向函数的__code__传递参数?

33 投票
6 回答
14234 浏览
提问于 2025-04-16 16:55

下面的代码可以正常工作:

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 个回答

7

我觉得在你更大的应用程序中,可能有一些设计上的考虑,让你不必太在意这个问题。比如说,可能有一些“已知良好且有效”的函数集合,这些函数作为一个模块被分发,执行的代理程序都知道这些函数的存在。

话虽如此,有一个比较简单的解决办法是:

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

我完全反对这样使用__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__

11

你能把这个函数改成接收任何参数吗?这样的话,变量就可以从本地或全局环境中查找,你可以把它们传给exec

>>> def spam():
...   print "spam and", eggs
... 
>>> exec(spam.__code__, {'eggs':'pasta'})
spam and pasta

(那为什么不直接把整个函数作为字符串发送呢?可以把"def spam(eggs): print 'spam and', eggs"这个函数用Pickle处理,然后在另一边用exec执行这个字符串(当然要先验证一下)。)

撰写回答