你如何让Python写下它在内存中的函数代码?

时间:2008-12-30 10:55:44

标签: python artificial-intelligence

当我通过程序中的选项(计算生物学实验)时,我通常会将它们传递给.py文件 所以我有这个.py文件,其内容如下:

starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000

然后我执行文件并获取数据。由于程序全部在我的机器上,没有其他人可以访问它,所以它是安全的 我也可以很容易地写一个类似的文件:

def writeoptions(directory):
    options=""
    options+="starting_length=%s%s"%(starting_length,os.linesep)
    options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
    options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
...
    open("%s%soptions.py"%(directory,os.sep),'w').write(options)

我想传递一个函数作为参数之一:

starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000

def pippo(a,b):
    return a+b
functionoperator=pippo

当然,在真正的实验中,函数pippo会复杂得多。不同于实验到实验。

但我无法做的是自动编写该功能。总之,如果其中一个选项是函数,我不知道如何推广writeoptions函数以继续编写选项。我当然可以复制原始文件,但这样做效率低,效率低(因为它包含许多未使用的额外选项),并且通常无法解决问题。

如何让python写下函数的代码,因为它写下变量的值?

5 个答案:

答案 0 :(得分:13)

vinko@mithril$ more a.py

def foo(a):
  print a

vinko@mithril$ more b.py

import a
import inspect

a.foo(89)
print inspect.getsource(a.foo)

vinko@mithril$ python b.py
89
def foo(a):
  print a

答案 1 :(得分:2)

您可能还会考虑其他一些数据持久性方法。在我自己的(天文学)研究中,我一直在试验两种不同的存储脚本以实现再现性的方法。第一种方法是将它们专门放在subversion存储库中,然后让作业提交脚本自动提交它们。例如,如果您只想在bash中执行此操作:

alias run_py='svn ci -m "Commit before running"; python2.5 $*'

并在脚本内部,为该文件输出前缀为current subversion revision number的输出,您将记录每个运行的脚本以及输入的内容。你可以根据需要将其从颠覆中拉回来。

跟踪函数输入的另一种功能基本上不那么全功能的方法可能是LodgeIt,一种接受XML-RPC输入并附带Python绑定的pastebin。 (它可以在本地安装,并且支持回复和更新现有的粘贴。)

但是,如果您正在寻找要包含的相对少量的代码,Vinko使用inspect的解决方案应该可以很好地工作。 Doug Hellman covered the inspect module在他的Python Module of the Week系列中。您可以创建一个装饰器来检查每个选项和参数,然后根据需要将其打印出来(我将使用inspect.getargspec来获取参数的名称。)

import inspect
from functools import wraps

def option_printer(func):
    @wraps(func)
    def run_func(*args, **kwargs):
        for name, arg in zip(inspect.getargspec(func)[0], args) \
                       + sorted(kwargs.items()):
            if isinstance(arg, types.FunctionType): 
                print "Function argument '%s' named '%s':\n" % (name, func.func_name)
                print inspect.getsource(func)
            else:
                print "%s: %s" % (name, arg)
        return func(*args, **kwargs)
    return run_func

这可能会更优雅,但在我的测试中,它适用于简单的参数和变量集。另外,lambdas可能会遇到一些麻烦。

答案 2 :(得分:0)

你在问这个吗?

def writeoptions(directory):
    options=""
    options+="starting_length=%s%s"%(starting_length,os.linesep)
    options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
    options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
    options+="def pippo(a,b):%s" % ( os.linesep, )
    options+="    '''Some version of pippo'''%s" % ( os.linesep, )
    options+="    return 2*a+b%s" % ( os.linesep, )
    open("%s%soptions.py"%(directory,os.sep),'w').write(options)

还是其他什么?

答案 3 :(得分:0)

虽然可以按照你的要求行事(如Vinko所示),但我会说分享代码更清晰。将pippo和他的伙伴放在两个程序都可以访问的子模块中。

答案 4 :(得分:0)

为什么不将生成的Python源保存在模块中( file.py disassemblers和字节码(例如inspect)的主题。 >),以后再导入它?

我建议您采用更标准的方式来处理您所谓的选项。例如,您可以使用JSON模块并保存或恢复数据。或者查看marshalpickle模块。