私は、ディスク上のpickleを永続ストレージとして使用する永続的な辞書の(プロダクトではなく、プロトタイプではなく)バージョンを実装しようとしていました。しかし、pickle.load
はそれ自身の目的で__setitem__
を呼び出します。これは、辞書への変更が永続的な記憶域に確実に反映されるように(もちろん)オーバーライドされているメソッドです - したがって、pickle.dump
が呼び出されます。もちろん、pickle.dump
に電話をかけることはできません。準備が整っていない `pickle.load`を呼び出す` __setitem__`をどう扱うか?
これを解決する方法はありますか?ブルートフォース以外の方法はありますか?私はPickling Class Instancesを読んで、特殊な方法を使って解決策を探しましたが、何も見つかりませんでした。
以下のコードは、unpicklingが進行中かどうかを監視し、その場合はpickle.dump
をスキップします。それはうまく動作しますが、それはハッキリと感じます。派手な辞書の実装を取得しようとしたときdict
から直接継承
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()
クラスをdictから継承するのではなく、クラスに属性を与え、そこにデータを格納する方が簡単かもしれません。次に、PersistentDictの代わりに格納されたdictをpickleして、2つのレイヤーを分離することができます。 – BrenBarn
@BrenBarnそれはまさに私が考えていたものですが、私はいつもそれを構成に置き換えるという点で、まずは継承に対して非常に偏っています。今回は、継承を試してみたかったのです。私が知っている継承に賛成する唯一の議論は、 '__getattr__'を使った自動転送は特別なメソッド(' __getitem__'、 '__contains__'、' __eq__'など)を転送しないということです。転送する手間が少しありますそれらはすべて手動で行います。しかし、これは継承が構成よりも面倒な別の例として終わるようです。 – max