我試圖實現一個使用磁盤上的pickle作爲持久存儲的持久性字典的(原型,而非生產版本)。但是,pickle.load
出於其自身目的調用__setitem__
,這是(當然)被覆蓋以確保將字典更改傳播回持久性存儲的方法 - 因此它調用pickle.dump
。當然,因爲在取出期間每個項目都被設置,因此撥打pickle.dump
並不好。如何處理調用`__setitem__`的pickle.load`還沒有準備好?
有沒有什麼辦法可以解決這個問題,除了通過蠻力(如下)?我試着讀Pickling Class Instances尋找一種使用特殊方法的解決方案,但沒有找到任何解決方案。
下面的代碼監視unpickling是否正在進行,並在這種情況下跳過pickle.dump
;雖然它工作正常,但感覺很不舒服。
import os, pickle
class PersistentDict(dict):
def __new__(cls, *args, **kwargs):
if not args: # when unpickling
obj = dict.__new__(cls)
obj.uninitialized = True
return obj
path, *args = args
if os.path.exists(path):
obj = pickle.load(open(path, 'rb'))
del obj.uninitialized
return obj
else:
obj = dict.__new__(cls, *args, **kwargs)
obj.path = path
obj.dump()
return obj
def __init__(self, *args, **kwargs):
pass
def __setitem__(self, key, value):
super().__setitem__(key, value)
self.dump()
def __delitem__(self, key):
super().__delitem__(key)
self.dump()
def dump(self):
if not hasattr(self, 'uninitialized'):
pickle.dump(self, open(self.path, 'wb'))
def clear(self):
os.remove(self.path)
pd = PersistentDict('abc')
assert pd == {}
pd[1] = 2
assert pd == {1: 2}
pd[2] = 4
assert pd == {1: 2, 2: 4}
del pd[1]
assert pd == {2: 4}
xd = PersistentDict('abc')
assert xd == {2: 4}
xd[3] = 6
assert xd == {2: 4, 3: 6}
yd = PersistentDict('abc')
assert yd == {2: 4, 3: 6}
yd.clear()
給你的類指定一個字典屬性並將數據存儲在那裏可能比較容易,而不是讓你的類從字典繼承。然後,你可以醃製存儲的字典,而不是你的PersistentDict,分離兩層。 – BrenBarn
@BrenBarn這正是我的想法,但我非常偏向於繼承的開始,直到我總是用組合替換它。所以這一次,我想繼承一下。我知道唯一支持繼承的論點是,使用'__getattr__'的自動轉發不會轉發特殊的方法(比如'__getitem__','__contains__','__eq__'等等),而且轉發有點麻煩他們全部手動。但這似乎最終成爲繼承處理比構圖更令人沮喪的另一個例子。 – max