Python对象持久性

scu*_*bbo 11 python persistence

我正在寻求有关在Python中实现对象持久性的方法的建议.更确切地说,我希望能够将Python对象链接到文件,使得打开该文件表示的任何Python进程共享相同的信息,任何进程都可以更改其对象,并且更改将传播到其他进程,即使关闭"存储"对象的所有进程,该文件仍将保留,并可由另一个进程重新打开.

我在Python的发行版中找到了三个主要的候选者 - anydbm,pickle和shelve(dbm似乎很完美,但它只是Unix,我在Windows上).但是,它们都有缺陷:

  • anydbm只能处理字符串值的字典(我正在寻找存储字典列表,所有字典都有字符串键和字符串值,但理想情况下我会寻找一个没有类型限制的模块)
  • 搁置要求在更改传播之前重新打开文件 - 例如,如果两个进程A和B加载相同的文件(包含搁置的空列表),并且A将一个项添加到列表并调用sync(),B将在重新加载文件之前,仍然会将列表视为空.
  • pickle(我目前用于我的测试实现的模块)具有与shelve相同的"重载要求",并且也不会覆盖以前的数据 - 如果进程A将15个空字符串转储到文件上,然后字符串'hello',进程B必须加载文件十六次才能获得'hello'字符串.我目前正在处理这个问题,通过重复读取的任何写操作,直到文件结束("在写入之前擦除平板"),并使每次读取操作重复直到文件结束,但我觉得必须有更好的方法.

我的理想模块的行为如下("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)
Run Code Online (Sandbox Code Playgroud)

我可以通过创建自己的模块来实现这种行为,该模块使用pickle,并编辑转储和加载行为,以便它们使用我上面提到的重复读取 - 但我发现很难相信这个问题从未发生过,并且已经修复之前,更有才华的程序员.而且,这些重复读取对我来说似乎效率低下(虽然我必须承认我对操作复杂性的了解有限,并且这些重复读取可能会在"幕后"进行,否则显然更平滑的模块如shelve).因此,我得出结论,我必须缺少一些可以解决问题的代码模块.如果有人能指出我正确的方向,或者提供有关实施的建议,我将不胜感激.

Mar*_*ers 11

请改用ZODB(Zope对象数据库).以ZEO为后盾,满足您的要求:

  • Python对象的透明持久性

    ZODB使用下面的泡菜,因此任何可挑剔的东西都可以存储在ZODB对象库中.

  • 完全与ACID兼容的事务支持(包括保存点)

    这意味着当一个进程良好且准备就绪时,从一个进程的更改传播到所有其他进程,并且每个进程在整个事务中对数据具有一致的视图.

ZODB已经存在了十多年了,所以你猜对了这个问题已经解决过了.:-)

ZODB让你插入存储空间; 最常见的格式是FileStorage,它将所有内容存储在一个Data.fs中,并为大对象提供可选的blob存储.

一些ZODB存储器是围绕其他存储器的包装器以添加功能; 例如,DemoStorage会保留内存中的更改,以便于进行单元测试和演示设置(重新启动并再次获得清洁).BeforeStorage为您提供了一个及时窗口,仅给定时间点之前从事务中返回数据.后者有助于为我恢复丢失的数据.

ZEO是一个引入客户端 - 服务器架构的插件.使用ZEO可以让您一次从多个进程访问给定的存储; 如果您只需要从一个进程进行多线程访问,那么您将不需要此层.

使用RelStorage可以实现同样的目的,它将ZODB数据存储在PostgreSQL,MySQL或Oracle等关系数据库中.