我正在寻求有关在Python中实现对象持久性的方法的建议。更确切地说,我希望能够将Python对象链接到文件,使得打开该文件表示的任何Python进程共享相同的信息,任何进程都可以更改其对象,并且更改将传播到其他进程,即使关闭“存储”对象的所有进程,该文件仍将保留,并可由另一个进程重新打开。
我在发布Python时找到了三个主要的候选者 - anydbm,pickle和shelve(dbm似乎很完美,但它只支持Unix,我在Windows上)。但是,它们都有缺陷:
我的理想模块的行为如下(“A>>>”表示由流程A执行的代码,“B>>>”代码由流程B执行):
A>>> import imaginary_perfect_module as mod
B>>> import imaginary_perfect_module as mod
A>>> d = mod.load('a_file')
B>>> d = mod.load('a_file')
A>>> d
{}
B>>> d
{}
A>>> d[1] = 'this string is one'
A>>> d['ones'] = 1 #anydbm would sulk here
A>>> d['ones'] = 11
A>>> d['a dict'] = {'this dictionary' : 'is arbitrary', 42 : 'the answer'}
B>>> d['ones'] #shelve would raise a KeyError here, unless A had called d.sync() and B had reloaded d
11 #pickle (with different syntax) would have returned 1 here, and then 11 on next call
(etc. for B)
我可以通过创建自己的模块来实现这种行为,该模块使用pickle,并编辑转储和加载行为,以便它们使用我上面提到的重复读取 - 但我发现很难相信这个问题从未发生过,并且之前被更多有才华的程序员修复过。而且,这些重复读取对我来说似乎效率低下(虽然我必须承认我对操作复杂性的了解有限,并且这些重复读取可能会在“幕后”进行,否则显然更平滑的模块如shelve)。因此,我得出结论,我必须缺少一些可以解决问题的代码模块。如果有人能指出我正确的方向,或者提出有关实施的建议,我将不胜感激。
答案 0 :(得分:11)
请改用ZODB
(Zope对象数据库)。以ZEO为后盾,满足您的要求:
Python对象的透明持久性
ZODB使用下面的泡菜,所以任何可挑剔的东西都可以存储在ZODB对象库中。
完全与ACID兼容的事务支持(包括保存点)
这意味着当一个流程良好且准备就绪时,一个流程的更改会传播到所有其他流程,并且每个流程在整个事务中对数据都有一致的视图。
ZODB已经存在了十多年了,所以你猜对了这个问题已经解决了。 : - )
ZODB让你插上存储空间;最常见的格式是FileStorage,它将所有内容存储在一个Data.fs中,并为大对象提供可选的blob存储。
一些ZODB存储是围绕其他存储的包装器以添加功能;例如,DemoStorage会保留内存中的更改,以便于进行单元测试和演示设置(重新启动并再次获得清理)。 BeforeStorage为您提供了一个及时窗口,仅在给定时间点之前从事务返回数据。后者有助于为我恢复丢失的数据。
ZEO是一个引入客户端 - 服务器架构的插件。使用ZEO可以让您一次从多个进程访问给定的存储;如果您只需要从一个进程进行多线程访问,则不需要此层。
使用RelStorage可以实现同样的目的,它将ZODB数据存储在关系数据库中,如PostgreSQL,MySQL或Oracle。
答案 1 :(得分:2)
对于初学者,您可以将搁置数据库移植到ZODB数据库,如下所示:
#!/usr/bin/env python
import shelve
import ZODB, ZODB.FileStorage
import transaction
from optparse import OptionParser
import os
import sys
import re
reload(sys)
sys.setdefaultencoding("utf-8")
parser = OptionParser()
parser.add_option("-o", "--output", dest = "out_file", default = False, help ="original shelve database filename")
parser.add_option("-i", "--input", dest = "in_file", default = False, help ="new zodb database filename")
parser.set_defaults()
options, args = parser.parse_args()
if options.in_file == False or options.out_file == False :
print "Need input and output database filenames"
exit(1)
db = shelve.open(options.in_file, writeback=True)
zstorage = ZODB.FileStorage.FileStorage(options.out_file)
zdb = ZODB.DB(zstorage)
zconnection = zdb.open()
newdb = zconnection.root()
for key, value in db.iteritems() :
print "Copying key: " + str(key)
newdb[key] = value
transaction.commit()
答案 2 :(得分:0)
我建议使用TinyDB,它使用起来更好,更简单。