2012-05-31 44 views
10

我正在尋求關於在Python中實現對象持久性的方法的建議。更準確地說,我希望能夠將Python對象鏈接到文件,以便任何打開該文件表示形式的Python進程都共享相同的信息,任何進程都可以更改其對象,並且這些更改會傳播到其他進程,即使所有「存儲」對象的進程都關閉,文件仍然會保留,並且可以由其他進程重新打開。我發現了三個主要的候選人 - 我的Python發行版 - anydbm,pickle和shelve(dbm看起來是完美的,但它只是Unix,而我在Windows上)。然而,他們都有缺陷:Python對象持久性

  • anydbm只能處理字符串值的字典(我正在尋找存儲詞典列表,它們都具有字符串鍵和字符串值,但最好我會尋求一個沒有類型限制的模塊)
  • 擱置需要在更改傳播之前重新打開文件 - 例如,如果兩個進程A和B加載相同的文件(包含已擱置的空列表),並且A將一個項目添加到列表並調用sync(),B仍然會看到列表爲空,直到它重新加載文件。
  • pickle(我當前用於測試實現的模塊)與shelve具有相同的「重新加載要求」,也不會覆蓋以前的數據 - 如果進程A將15個空字符串轉儲到文件上,然後字符串' hello',進程B將不得不加載文件16次以獲得'hello'字符串。我正在處理這個問題,通過在重複讀取之前進行任何寫操作,直到文件結束(「在寫入之前清除slate clean」),並重復每次讀操作直到文件結束,但是我覺得必須有一個更好的方法。

我的理想模塊將表現爲如下(以 「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的模塊來實現這種行爲,並編輯轉儲和加載行爲,以便他們使用我上面提到的重複讀取 - 但是我發現很難相信這個問題從未發生過,並且已經被修復,之前更有天賦的程序員。此外,對我來說,這些重複的讀取看起來效率不高(儘管我必須承認我對操作複雜性的瞭解是有限的,而且這些重複的讀取可能會在「幕後」進行,否則顯然會更順暢)。因此,我得出結論,我必須缺少一些能夠爲我解決問題的代碼模塊。如果有人能指出我的方向是正確的,或者對實施提出建議,我將不勝感激。

+4

給看看,以'蒙戈 - db'。它並沒有像上面的例子那樣完全集成到語言中,但它會爲您提供一個比文件系統酸洗更爲強大和容忍的數據庫,並且對鎖定很敏感。 – slezica

回答

11

改爲使用ZODB(Zope對象數據庫)。與ZEO支持它滿足您的要求:

  • Python的透明持久性對象

    ZODB使用泡菜下方,所以,只要是泡菜,能夠可以存儲在ZODB對象存儲。

  • 完全ACID兼容的事務支持(包括保存點)

    這意味着從一個進程更改傳播到所有其他進程時,他們都準備好了,每個過程對整個數據的一致性視圖交易。

ZODB已經存在了十多年了,所以你對這個問題的猜測是對的,之前已經解決了。 :-)

ZODB讓你插入存儲;最常見的格式是FileStorage,它將所有內容都存儲在一個Data.fs中,併爲大型對象提供可選的blob存儲。

一些ZODB存儲是其他人添加功能的包裝; DemoStorage例如保持內存中的變化,以促進單元測試和演示設置(重新啓動,並且您再次擁有乾淨的平板)。 BeforeStorage爲您提供時間窗口,僅在給定時間點返回之前的交易的數據。後者有助於爲我恢復丟失的數據。

ZEO就是這樣一個引入客戶端 - 服務器體系結構的插件。使用ZEO可以讓您一次訪問多個進程中的給定存儲;如果您只需要一個進程的多線程訪問,則不需要此圖層。

使用RelStorage可以實現同樣的效果,它將ZODB數據存儲在關係數據庫(如PostgreSQL,MySQL或Oracle)中。

+0

ZODB聽起來就像我想要的(RelStorage聽起來像是一件有趣的事情,可以爲將來查找) - 謝謝!我會測試它,並返回標記爲答案,如果它適用於我。 – scubbo

+0

太棒了,謝謝你的建議! – scubbo

+0

這聽起來像我想要的;在什麼擱置提供。 – fatuhoku

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()