如何让Python将其内存中的函数代码写入文件?

5

当我在程序中传递选项(一个计算生物学实验)时,通常会通过.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在输出变量值的同时输出函数的代码呢?

如果选项已经在Python中,为什么要将它们写入另一个文件?如果选项不在Python中,那么我不清楚你不能做什么。如果您能够包含无法完成的事情的伪代码,那将会有所帮助。 - S.Lott
请参见http://stackoverflow.com/questions/48211/free-python-decompiler-that-is-not-an-online-service。 - S.Lott
请参见 https://dev59.com/qXRC5IYBdhLWcg3wUvUS。 - S.Lott
5个回答

15
vinko@mithril$ more a.py
定义函数foo(a): 输出a
vinko@mithril$ more b.py
导入a模块和inspect模块 调用a模块中的函数foo,参数为89 输出函数foo的源代码
vinko@mithril$ python b.py 输出89 输出函数foo的源代码:
def foo(a): 输出a

谢谢,但是这个解决方案需要我为每个传递参数的函数准备一个额外的文件。此外,这基本上就是我之前解释过的简单复制原始文件的问题。 让我们看看是否有人能找到不同的解决方案,还是谢谢你。 Pietro - Pietro Speroni
嗯?为什么每个函数都需要一个额外的文件呢? - Vinko Vrsalovic
请注意,如果您删除或编辑了源文件,则通常无法使用此方法检索源代码。inspect.getsource必须读取源文件 - Python函数不会将自己的源代码保存在内存中。虽然有一些缓存机制,但除非文件内容恰好被缓存在linecache中,否则只有在源文件仍然存在的情况下才能起作用。 - user2357112

2
您还可以考虑其他数据持久化方式。在我自己(天文学)的研究中,我一直在尝试两种不同的存储脚本以实现可重现性的方法。第一种方法是将它们专门放在一个子版本库中,然后让作业提交脚本自动提交它们。例如,如果您只想在bash中执行此操作:
alias run_py='svn ci -m "Commit before running"; python2.5 $*'

在脚本内部,可以使用当前文件的Subversion版本号作为输出前缀,这样就可以记录每个运行的脚本及其输入内容。需要时,可以从Subversion中检索出来。
另一种追踪函数输入的方式是使用类似于LodgeIt的工具,它是一个接受XML-RPC输入的pastebin,并带有Python绑定。虽然功能不如前者完善,但它可以在本地安装,并支持回复和更新现有的paste。
但是,如果你正在寻找一个相对较小的代码量来包含,Vinko的解决方案使用inspect应该非常有效。Doug Hellman在他的Python模块系列中(链接)介绍了inspect模块(链接)。你可以创建一个装饰器来检查每个选项和参数,然后根据需要将其打印出来(我将使用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

这可能可以更加优雅一些,但在我的测试中它适用于简单的参数和变量集合。此外,它可能会在处理lambda表达式时遇到一些问题。

0

虽然可以像Vinko所示那样做你要求的事情,但我认为更好的方法是共享代码。将pippo及其伙伴放在一个子模块中,两个程序都可以访问。


谢谢,但正如我所解释的,我对Vinko的解决方案并不是很满意,原因如上所述。话虽如此,代码的整体结构是有一个主程序,每种类型的系统都有一个模块文件,每个选项都有一个选项文件。(继续) - Pietro Speroni
我并不是很期待为每个模块都额外创建一个文件,以便于传递选项参数。 - Pietro Speroni
在我的程序中,我倾向于保存每次执行的代码,原因在此不便赘述。这样它们就不会在计算机上共享模块,而且我可以轻松地将实验传递给同事。 - Pietro Speroni
但是在所有这些方面,我发现能够像保存参数一样保存函数的挑战本身就很有趣。 - Pietro Speroni

0

不妨先把生成的 Python 源代码存储在模块(file.py)中,然后再导入,这比深入研究 disassemblers和字节码(例如 inspect)更为简单。

我建议您探索一下更标准的处理{{em: 选项}}的方法。例如,您可以使用JSON模块保存或恢复数据。或者,您也可以查看marshalpickle模块。


谢谢。虽然我自己资助的存储选项的方式可能不是最佳的,但我想学习编写函数源代码的主要原因是为了它本身。这是对编写自己代码的程序概念的一般调查。 - Pietro Speroni
谢谢提供链接。我已经阅读了检查部分,并找到了我正在寻找的解决方案的一部分。因此,我已经在路上了。 :) - Pietro Speroni

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)

还是其他什么?


基本上是另一回事。您的代码不会将函数pippo作为参数传递,以编写新的选项文件。实质上,我可以在代码本身中拥有函数Pippo,因为我必须在每种情况下更改writeoptions函数。现在更清楚了吗? - Pietro Speroni
一点也不清楚。你有pippo的源代码吗?如果有,那么你就不需要将它写入文件——你已经有源代码了。 - S.Lott
每个实验都放置在不同的目录中,我只复制我所需的所有信息。程序副本、数据副本和选项(!)副本。但是选项文件并不会被复制,而是由程序生成以避免不必要的部分。因此问题来了,除了理论上的兴趣。 - Pietro Speroni
程序、数据和选项的副本(!)。但选项文件不会被复制。好的,随你怎么说。选项既被复制又未被复制。 - S.Lott
是的,因为如果我只是从原始文件中复制它,我也会复制所有的注释和存在的备选版本。谢谢。 - Pietro Speroni
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接