在Python中保存和重新加载变量,保留变量名称

7

我曾经使用Matlab多年,现在开始接触Python,并且还在学习两者之间的区别。由于与其他人一起使用,我必须使用Jupyter笔记本。

有一件事情让我困惑不解,就是如何将变量保存到文件中以便在另一个脚本中加载。我需要运行一个处理数据的脚本,并生成多个变量。然后我想要将这些变量保存到文件中,并能够在另一个脚本中重新加载它们。

假设我的变量名为'wbl','wbr'和'body_ang'

在Matlab中,这很简单,使用以下代码:

save(filename,'wbl','wbr','body_ang')

然后我只需要使用以下代码加载变量:

load(filename)

我找不到Python中具有相同功能的东西。您可以使用numpy.save保存变量,但它不会保留变量名称。因此,除非您知道保存它们的顺序,否则无法重新创建它们。

我想要它们作为单独的变量,而不仅仅是数组的一部分(除非它们在加载后可以轻松地重新创建)。

这似乎是一个简单明显的事情,但我不知道如何做到。


1
你试过pickle吗? - Epsi95
4个回答

5
如Epsi95所说,您可以使用Python中的pickle模块,将Python对象保存到文件中。
如果您想记录全局变量的值,则可以使用以下函数(它们的工作方式与您从Matlab给出的示例相同):
import pickle

def save(filename, *args):
    # Get global dictionary
    glob = globals()
    d = {}
    for v in args:
        # Copy over desired values
        d[v] = glob[v]
    with open(filename, 'wb') as f:
        # Put them in the file 
        pickle.dump(d, f)

def load(filename):
    # Get global dictionary
    glob = globals()
    with open(filename, 'rb') as f:
        for k, v in pickle.load(f).items():
            # Set each global variable to the value from the file
            glob[k] = v
    

你可以同样地称呼它们:

save(filename,'wbl','wbr','body_ang')

load(filename)

这只适用于全局变量,所以下面的方法不起作用:

def foo():
    u = 8
    # "u" is not a global variable, so it can't be saved
    # This will raise an Exception 
    save("bar", "u")

foo()
# Even if we did save "u", where do we put it now?
# The function isn't running, so we'd have it put it in globals 
load("bar")

不过,使用global关键字可以帮助你:

def foo():
    global u = 8
    # "u" is a global variable, so everything will work fine
    save("bar", "u")
    # Delete it if you don't want "u" to stick around after function
    del u

foo()
# Put "u" back in globals
load("bar")


如果您想保存除全局变量之外的其他变量,您需要像使用pickle一样,将所有值映射到一个字典中,并在以后检索整个字典。
编辑:修复了代码中的一些错误。

非常感谢您对此的帮助。然而,当我尝试运行代码时,出现了以下错误: - Simon Walker
TypeError: write()的参数必须是str,而不是bytes。pickle.dump(d,f) 13行 - Simon Walker
我通过在保存函数中将open(filename, 'w')更改为open(filename, 'wb')来解决了那个错误,但是现在在加载文件时出现了这个错误: - Simon Walker
对于k,v in pickle.load(f):'utf-8'编解码器无法解码位置0中的字节0x80:无效的起始字节 - Simon Walker
我可以将保存函数中的打开行更改为: with open(filename, 'rb') as f - Simon Walker
显示剩余3条评论

2

这不是Python的特性,而是Jupyter Notebook的特性。使用%store命令可以将一个变量保存在一个笔记本中,以便在另一个笔记本中检索:

存储:

x = 10
%store x

Stored 'x' (int)

检索:

%store -r x
x

10

谢谢,对于简单的情况来说这确实很有帮助。仍然让我感到惊讶的是在Python中没有更简单的方法来做到这一点。也许我只是太习惯用Matlab的方式了。 - Simon Walker

0

1
谢谢您的建议。然而,我认为这里的问题在于它没有使用变量名重新创建变量。请参考Fricative Melon的答案,该答案使用pickle精确地重构了变量。 - Simon Walker

0
这是一个小助手模块,用于以json格式存储/加载变量:
import json
import inspect

def save_vars(fname, *args):
    d = {}
    caller_vars = inspect.stack()[1].frame.f_locals
    for arg in args:
        if arg in caller_vars:
            d[arg] = caller_vars[arg]
    with open(fname, 'w') as f:
        f.write(json.dumps(d))

def load_vars(fname):
    caller_vars = inspect.stack()[1].frame.f_locals
    with open(fname, 'r') as f:
        d = json.loads(f.read())
    for k,v in d.items():
        caller_vars[k] = v

将此模块保存在您当前的目录中,例如 myvars.py。

以下是如何使用它的方法:

sgal@diff$ python3
Python 3.9.0 (default, Nov 30 2020, 15:21:09)
>>> from myvars import *
>>> a,b,c=1,2,3
>>> save_vars('vars','a','b','c')

sgal@diff$ cat vars
{"a": 1, "b": 2, "c": 3}

sgal@diff$ python3
Python 3.9.0 (default, Nov 30 2020, 15:21:09)
>>> from myvars import *
>>> load_vars('vars')
>>> a
1
>>> b
2
>>> c
3

我尝试运行这个程序,但它抛出了一系列错误。我接受了建议pickle作为答案,因为我知道很多人使用这个模块。 - Simon Walker

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