如何在Python中保存和恢复多个变量?

147

我需要将大约十几个对象保存到文件中,然后稍后再恢复它们。 我尝试使用pickle和shelve的循环,但是没能正常工作。

编辑。
我想保存的所有对象都属于同一个类(我之前应该提到这一点),我没有意识到可以像这样保存整个类:

import pickle
def saveLoad(opt):
    global calc
    if opt == "save":
        f = file(filename, 'wb')
        pickle.dump(calc, f, 2)
        f.close
        print 'data saved'
    elif opt == "load":
        f = file(filename, 'rb')
        calc = pickle.load(f)
    else:
        print 'Invalid saveLoad option'

1
你说你尝试过使用for循环。请发布那段代码,并说明“它没有正常工作”的原因(即发生了什么以及你想要发生什么)。 - Blair
如果您在Windows上,请确保以二进制模式打开文件。 - John La Rooy
@gnibbler:二进制模式仅适用于非默认协议(http://docs.python.org/library/pickle.html#usage)。 - Eric O. Lebigot
7个回答

226
如果您需要保存多个对象,可以将它们放在一个列表或元组中,例如:
import pickle

# obj0, obj1, obj2 are created here...

# Saving the objects:
with open('objs.pkl', 'w') as f:  # Python 3: open(..., 'wb')
    pickle.dump([obj0, obj1, obj2], f)

# Getting back the objects:
with open('objs.pkl') as f:  # Python 3: open(..., 'rb')
    obj0, obj1, obj2 = pickle.load(f)
如果你有大量数据需要处理,可以通过在调用 dump() 时传入参数 protocol=-1 来减小文件大小;这样 pickle 将会使用最好的可用协议,而不是默认的历史协议(该协议更向后兼容)。在这种情况下,文件必须以二进制模式打开(分别为 wbrb)。
在 Python 3 中,也应该使用二进制模式,因为它的默认协议生成二进制(即非文本)数据(写入模式为 'wb',读取模式为 'rb')。

15
在Python 3.5中,我必须以"byte"模式打开文件,例如 with open('objs.pickle', 'wb') as f:(注意 wb)。 - kbrose
1
嗨@Eric,with open('objs.pkl') as f:相对于简单的obj1, obj2 = pickle.load(open("objs.pkl","rb"))有什么必要性?这两者之间有什么区别吗? - mpx
1
使用第二种形式时,您不需要关闭文件。这被认为不是一个好的实践方法,因为操作系统可以打开并行文件数量通常是相当有限的(尝试使用循环打开文件但不关闭它们!)。话虽如此,在实践中,如果您不打开太多文件,则不关闭文件通常是可以工作的。 - Eric O. Lebigot

60

有一个名为pickle的内置库。使用pickle,您可以将对象转储到文件中,并稍后加载它们。

import pickle

f = open('store.pckl', 'wb')
pickle.dump(obj, f)
f.close()

f = open('store.pckl', 'rb')
obj = pickle.load(f)
f.close()

1
我在Python 3.4中使用以下代码:f = open('store.pckl', 'wb') 打开一个文件进行写入。请参考https://dev59.com/8WYr5IYBdhLWcg3wKHEp。同时,使用 f = open('store.pckl', 'rb') 打开一个文件进行读取。请参考https://dev59.com/lFrUa4cB1Zd3GeqPhS1R。 - user3731622
这个特定于3.4+吗?我差点投票反对答案,因为当你不使用“b”时它会生成错误。 - Wilmer E. Henao
1
问题是“如何在Python中保存和恢复多个变量?” 请更新您的答案,说明如何在pickle中处理多个变量,而不是一个变量。 - Ferro

14

将多个变量保存到Pickle文件的另一种方法是:

import pickle

a = 3; b = [11,223,435];
pickle.dump([a,b], open("trial.p", "wb"))

c,d = pickle.load(open("trial.p","rb"))

print(c,d) ## To verify

这种方法不能安全地关闭文件。open函数会生成一个文件句柄,需要通过存储该句柄并调用.close方法来关闭它,或者更好的方式是使用with open(...) as ...:语句块。第二种选项通常更好,因为即使发生异常,它也会自动为您关闭文件。 - cdgraham

13

您应该查看 shelvepickle 模块。如果您需要存储大量数据,最好使用数据库。


我想保存一个登录到云服务器的单个对象,以便处理如果我随着时间的推移多次登录,服务器会拒绝我的请求。使用pickle模块将对象转储到文件中是否可能存在任何安全问题?例如,如果有人获得了我的转储对象,那么他们可以在不使用密码的情况下登录到我的云存储中。 - alper

9

下面的方法似乎很简单,并且可以用于不同大小的变量:

import hickle as hkl
# write variables to filename [a,b,c can be of any size]
hkl.dump([a,b,c], filename)

# load variables from filename
a,b,c = hkl.load(filename)

1
hickle 包比 pickle 更健壮(更少出错)且更简单(更少代码)。 - user2340939

5
您可以使用 klepto,它提供了对内存、磁盘或数据库的持久化缓存。
dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db['1'] = 1
>>> db['max'] = max
>>> squared = lambda x: x**2
>>> db['squared'] = squared
>>> def add(x,y):
...   return x+y
... 
>>> db['add'] = add
>>> class Foo(object):
...   y = 1
...   def bar(self, x):
...     return self.y + x
... 
>>> db['Foo'] = Foo
>>> f = Foo()
>>> db['f'] = f  
>>> db.dump()
>>> 

然后,在解释器重新启动之后...
dude@hilbert>$ python
Python 2.7.6 (default, Nov 12 2013, 13:26:39) 
[GCC 4.2.1 Compatible Apple Clang 4.1 ((tags/Apple/clang-421.11.66))] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from klepto.archives import file_archive
>>> db = file_archive('foo.txt')
>>> db
file_archive('foo.txt', {}, cached=True)
>>> db.load()
>>> db
file_archive('foo.txt', {'1': 1, 'add': <function add at 0x10610a0c8>, 'f': <__main__.Foo object at 0x10510ced0>, 'max': <built-in function max>, 'Foo': <class '__main__.Foo'>, 'squared': <function <lambda> at 0x10610a1b8>}, cached=True)
>>> db['add'](2,3)
5
>>> db['squared'](3)
9
>>> db['f'].bar(4)
5
>>> 

在这里获取代码: https://github.com/uqfoundation

7
楼主没有要求使用内置的功能。 - Mike McKerns

0
这里是使用 dill(https://dill.readthedocs.io/en/latest/dill.html)包的解决方案。Pickle 应该类似工作。
""" Some objects to save """

import numpy as np
a = 6
b = 3.5
c = np.linspace(2,5,11)

""" Test the dump part """

import dill
file_name = 'dill_dump_test_file.dil'
list_of_variable_names = ('a', 'b', 'c')

with open(file_name,'wb') as file:
    dill.dump(list_of_variable_names, file)  # Store all the names first
    for variable_name in list_of_variable_names:
        dill.dump(eval(variable_name), file) # Store the objects themselves
        
#   Clear all the variables here     

""" Test the load part """

import dill
file_name = 'dill_dump_test_file.dil'
g = globals()

with open(file_name,'rb') as file:
    list_of_variable_names = dill.load(file)  # Get the names of stored objects
    for variable_name in list_of_variable_names:
        g[variable_name] = dill.load(file)    # Get the objects themselves
        

你的回答可以通过提供更多支持性信息来改进。请编辑以添加进一步的细节,例如引用或文档,以便他人能够确认你的回答是否正确。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

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