在Python脚本运行之间保持持久变量在内存中

74 投票
8 回答
88884 浏览
提问于 2025-04-16 21:29

有没有办法让一个结果变量一直保存在内存里,这样我每次运行脚本开头的时候就不用重新计算它了?我每次运行脚本时,都要对一个数据集进行一系列长达5到10秒的相同操作(这个数据集是从磁盘读取的)。

其实这不是太大的问题,因为我在使用交互式编辑器调试代码时还算得心应手;不过有时候,交互式的功能并不能满足我的需求。

我知道我可以把结果写到磁盘上的文件里,但如果可以的话,我希望避免这样做。我想要的是一种解决方案,第一次运行脚本时生成一个变量,并且这个变量能一直保存在内存中,直到我关闭终端或者明确告诉它要消失为止。类似这样的:

# Check if variable already created this session
in_mem = var_in_memory() # Returns pointer to var, or False if not in memory yet
if not in_mem:
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    in_mem = store_persistent(result)

我有一种感觉,shelve模块可能正是我需要的,但看起来要打开一个shelve变量,我必须指定一个文件名来保存这个持久对象,所以我不确定这是否符合我的需求。

有没有什么建议可以让shelve按我想要的方式工作?或者有没有其他的想法?

8 个回答

11

如果你只想保存一个对象(或者一组相关的对象)以便以后使用,使用 shelve 模块可能有点过于复杂了。你只需要把你关心的对象进行“腌制”(也就是序列化)就可以了。如果你还没有腌制文件,就先进行腌制并保存;如果你已经有腌制文件了,那就直接加载它。

import os
import cPickle as pickle  # for python 2

pickle_filepath = "/path/to/picklefile.pickle"

if not os.path.exists(pickle_filepath):
    # Read data set from disk
    with open('mydata', 'r') as in_handle:
        mytext = in_handle.read()
    # Extract relevant results from data set
    mydata = parse_data(mytext)
    result = initial_operations(mydata)
    with open(pickle_filepath, 'w') as pickle_handle:
        pickle.dump(result, pickle_handle)
else:
    with open(pickle_filepath) as pickle_handle:
        result = pickle.load(pickle_handle)

在 Python 3 中,只需 import pickle

12

要在内存中保存数据,程序必须一直在运行。内存是属于运行脚本的程序的,而不是命令行工具(shell)。命令行工具不能为你保存内存。

所以,如果你想修改代码并保持程序运行,你就得在代码改变时重新加载模块。如果内存中的数据是某个类的实例,而这个类发生了变化,你就需要找到方法把它转换成新类的实例。这有点麻烦。其实很多编程语言在处理这种“热补丁”的时候都做得不好(比如常见的Lisp语言),而且在这个过程中出错的机会也很多。

68

你可以通过使用 reload 这个全局函数来重新执行你的主脚本的代码,达到类似的效果。你需要写一个包装脚本,这个脚本会导入你的主脚本,然后向它请求想要缓存的变量,把这个变量的副本保存在包装脚本的模块范围内。接着,当你想要重新加载时(比如按下回车键),它会调用 reload(yourscriptmodule),这次会把缓存的对象传给它,这样你的主脚本就可以跳过那些耗时的计算。下面是一个简单的例子。

wrapper.py

import sys
import mainscript

part1Cache = None
if __name__ == "__main__":
    while True:
        if not part1Cache:
            part1Cache = mainscript.part1()
        mainscript.part2(part1Cache)
        print "Press enter to re-run the script, CTRL-C to exit"
        sys.stdin.readline()
        reload(mainscript)

mainscript.py

def part1():
    print "part1 expensive computation running"
    return "This was expensive to compute"

def part2(value):
    print "part2 running with %s" % value

wrapper.py 运行的时候,你可以编辑 mainscript.py,在 part2 函数中添加新代码,并且能够在预先计算好的 part1Cache 上运行你的新代码。

撰写回答