1

状況を説明する最良の方法は、例を使用することだと思います。

>>> class Person:
...     def __init__(self, brother=None):
...         self.brother = brother
... 
>>> bob = Person()
>>> alice = Person(brother=bob)
>>> import shelve
>>> db = shelve.open('main.db', writeback=True)
>>> db['bob'] = bob
>>> db['alice'] = alice
>>> db['bob'] is db['alice'].brother
True
>>> db['bob'] == db['alice'].brother
True
>>> db.close()
>>> db = shelve.open('main.db',writeback=True)
>>> db['bob'] is db['alice'].brother
False
>>> db['bob'] == db['alice'].brother
False

両方の比較で期待される出力は、True再び次のとおりです。ただし、pickle(これは によって使用されshelveます) は再インスタンス化されbobalice.brother個別に行われているようです。shelve/を使用してこれを「修正」するにはどうすればよいpickleですか? または同様のものdb['alice'].brotherを指すことは可能ですか?db['bob']両方を比較するだけでなく、実際には両方が同じである必要があることに注意してください。

Blckknghtが提案したように、辞書全体を一度に酸洗いしようとしましたが、各キーを別々に酸洗いしているように見えるため、問題は解決しません。

4

3 に答える 3

2

あなたが見ている問題は、shelveモジュールがその値を保存する方法に起因すると思います。各値は、シェルフ内の他の値とは独立してピクルされます。つまり、同じオブジェクトが複数のキーの下に値として挿入された場合、キー間で ID が保持されません。ただし、1 つの値に同じオブジェクトへの複数の参照がある場合、ID はその 1 つの値内で維持されます。

次に例を示します。

a = object() # an arbitrary object
db = shelve.open("text.db")
db['a'] = a
db['another_a'] = a
db['two_a_references'] = [a, a]
db.close()

db = shelve.open("text.db") # reopen the db
print(db['a'] is db['another_a']) # prints False
print(db['two_a_references'][0] is db['two_a_references'][1]) # prints True

a最初の出力では、データベースに挿入された2 つのバージョンのオブジェクトの ID を確認しようとします。1 つはキーの下に'a'直接、もう1 つは の下にあります'another_a'。個別の値が個別にピクルされ、それらの間のアイデンティティが失われたため、機能しません。

a2 番目の出力は、キーの下に格納された 2 つの参照'two_a_references'が維持されているかどうかをテストします。リストは一気に漬け込んだので、身元は保たれています。

したがって、問題に対処するには、いくつかのオプションがあります。1 つのアプローチは、同一性のテストを回避し、さまざまなオブジェクト タイプのメソッドに依存して、__eq__2 つのオブジェクトが同じオブジェクトでなくても意味的に等しいかどうかを判断することです。もう 1 つは、すべてのデータを 1 つのオブジェクト (辞書など) にまとめて保存し、使用するのではなくpickle.dump復元することです (または、このレシピをドキュメントからリンクされている永続的な辞書に適合させることができます。ほとんどそれを行います)。pickle.loadshelveshelve

于 2013-07-14T05:16:21.270 に答える
1

Python での適切な方法は、次のように Person クラス内に__eq__and関数を実装することです。__ne__

class Person(object):

    def __eq__(self, other):
        return (isinstance(other, self.__class__)
            and self.__dict__ == other.__dict__)

    def __ne__(self, other):
        return not self.__eq__(other)

通常はこれで十分ですが、これらが真のデータベース オブジェクトであり、主キーがある場合は、 の代わりにその属性をチェックする方が効率的ですself.__dict__

于 2013-07-14T04:44:43.260 に答える
1

問題

ID を保持するには、 read thisshelveで ID を保持する必要があります。pickle

解決

このクラスは、そのクラス サイトにすべてのオブジェクトを保存し、ID が同じ場合はそれらを復元します。そこからサブクラス化できるはずです。

>>> class PickleWithIdentity(object):
    identity = None
    identities = dict() # maybe use weakreference dict here
    def __reduce__(self):
        if self.identity is None:
            self.identity = os.urandom(10) # do not use id() because it is only 4 bytes and not random
            self.identities[self.identity] = self
        return open_with_identity, (self.__class__, self.__dict__), self.__dict__


>>> def open_with_identity(cls, dict):
    if dict['identity'] in cls.identities:
        return cls.identities[dict['identity']]
    return cls()

>>> p = PickleWithIdentity()
>>> p.asd = 'asd'
>>> import pickle
>>> import os
>>> pickle.loads(pickle.dumps(p))
<__main__.PickleWithIdentity object at 0x02D2E870>
>>> pickle.loads(pickle.dumps(p)) is p
True

状態が上書きされる可能性があるため、さらに問題が発生する可能性があります。

>>> p.asd
'asd'
>>> ps = pickle.dumps(p)
>>> p.asd = 123
>>> pickle.loads(ps)
<__main__.PickleWithIdentity object at 0x02D2E870>
>>> p.asd
'asd'
于 2013-07-14T18:30:52.117 に答える