0

このドキュメントでは、リストを再割り当てすることで、「可変属性を不変であるかのように使用する」という ZODB での可変リストの取り扱い方法を紹介します。値がリストである OOBTree 構造に、単純ではあるがかなり長い逆索引を作成しようとしました。Persistentlistなどを使用せずに上記の方法に触発され、「追加」をリストの再割り当てに置き換えただけで、問題なく機能し、結果のデータベースファイルは理想的に小さくなりました。確認したところ、インデックスに問題はないようですが、確信が持てません。本当にこんなに簡単にできるの?アドバイスをいただければ幸いです。

以下は、ZODB で逆インデックスを作成するために私が書いたコードの一部です。

#......
root['idx']=OOBTree()
myindex = root['idx']
i=0
#.....
doc = cursor.first()
while doc:
    docdict = {}
    for word in doc.words():
        docdict[word]=docdict.setdefault(word,0)+1
    for (word,freq) in docdict.iteritems():
        i+=1
        if word in myindex:
            myindex[word]= myindex[word]+ [(doc[0],freq)]
            # This seems to work just fine. 
            # This is where I'm confused. Can this really work all right?
        else:
            myindex[word]=[(doc[0],freq)] # This list is not a PersistentList.
        if i % 200000 == 0: transaction.savepoint(True)
    doc =cursor.next()
docs.close()
transaction.commit()
#......
4

1 に答える 1

0

はい、本当に簡単です。

ベースクラスはフックをPersistentオーバーライドし__setattr__て、データベースにコミットする必要がある変更が行われたことを検出します。リストなどの変更可能な属性への変更は__setattr__フックを使用しないため、検出されません。

デモ クラスでこれを示すのが最も簡単です。

>>> class Demo(object):
...     def __setattr__(self, name, value):
...          print 'Setting self.{} to {!r}'.format(name, value)
...          super(Demo, self).__setattr__(name, value)
... 
>>> d = Demo()
>>> d.foo = 'bar'
Setting self.foo to 'bar'
>>> d.foo = 'baz'
Setting self.foo to 'baz'
>>> d.foo
'baz'
>>> d.spam = []
Setting self.spam to []
>>> d.spam.append(42)
>>> d.spam
[42]

d.spam.append()呼び出しによって印刷出力が得られなかったことに注意してください。.append()呼び出しは、親インスタンスではなく、リストで直接機能します。Demo()

一方、再割り当て次のように検出されます。

>>> d.spam = d.spam
Setting self.spam to [42]

Persistent何かが変更されたことを通知する別の方法は、_p_changedフラグを直接設定することです。

myindex._p_changed = True

変更が検出されているかどうか疑わしい場合は、そのフラグをテストすることもできます。

assert myindex._p_changed, "Oops, no change detected?"

が(またはおそらく)の場合はAnAssertionErrorが発生します。これは、現在のトランザクションの開始以降に変更が検出されなかった場合にのみ当てはまります。myindex._p_changedFalse0

于 2013-10-25T17:19:48.093 に答える