2009-03-24 5 views
16

私は、アイテムが消滅したときにアイテムを削除する弱い参照のリストが必要です。現在、私がこれをやっている唯一の方法は、リストをフラッシュしておくことです(デッドリファレンスを手動で削除する)。pythonのweakrefリスト

私はWeakKeyDictionaryとWeakValueDictionaryがあることを知っていますが、私はWeakListを実際に使っています。これを行う方法はありますか?

はここに例を示します

import weakref 

class A(object): 
    def __init__(self): 
     pass 

class B(object): 
    def __init__(self): 
     self._references = [] 

    def addReference(self, obj): 
     self._references.append(weakref.ref(obj)) 

    def flush(self): 
     toRemove = [] 

     for ref in self._references: 
      if ref() is None: 
       toRemove.append(ref) 

     for item in toRemove: 
      self._references.remove(item) 

b = B() 

a1 = A() 
b.addReference(a1) 
a2 = A() 
b.addReference(a2) 

del a1 
b.flush() 
del a2 
b.flush() 
+0

は、あなたが "手動削除"、 "参照"、 "フラッシュ"、 "ダイ" を定義してくださいだろうか?この質問は実際にはそれほど意味がありません。 – hop

+0

die =弱参照は無効になります( "dead")。 reference =弱い参照(http://docs.python.org/library/weakref.html)。 flush =手動で削除する=リスト内のすべての参照に対して無効なものを削除します。 – Dan

+0

あなたはすでに何をすべきか分からない限り、まだあまり明確ではありません – hop

答えて

5

あなたが行っている方法と同様に、それを自分で実装することができますが、flushを呼び出しリストサブクラス(との)項目にアクセスしようとする前に。

明らかに、すべてのアクセスでこれを行う必要はありませんが、ウィークリファレンスでコールバックを設定して、何かが死んだときにリストをダーティにマークすることで、これを最適化できます。最後にアクセスしてから何かが死んだときに、リストをフラッシュするだけです。

このメソッドを使用して実装されたリストクラスを次に示します。 (実際のリストに変換してそのメソッドを呼び出すメソッドなど、いくつかのメソッドは非常に効率的に実装されていませんが、合理的な出発点である必要があります。

import weakref 

class WeakList(list): 
    def __init__(self, seq=()): 
     list.__init__(self) 
     self._refs = [] 
     self._dirty=False 
     for x in seq: self.append(x) 

    def _mark_dirty(self, wref): 
     self._dirty = True 

    def flush(self): 
     self._refs = [x for x in self._refs if x() is not None] 
     self._dirty=False 

    def __getitem__(self, idx): 
     if self._dirty: self.flush() 
     return self._refs[idx]() 

    def __iter__(self): 
     for ref in self._refs: 
      obj = ref() 
      if obj is not None: yield obj 

    def __repr__(self): 
     return "WeakList(%r)" % list(self) 

    def __len__(self): 
     if self._dirty: self.flush() 
     return len(self._refs) 

    def __setitem__(self, idx, obj): 
     if isinstance(idx, slice): 
      self._refs[idx] = [weakref.ref(obj, self._mark_dirty) for x in obj] 
     else: 
      self._refs[idx] = weakref.ref(obj, self._mark_dirty) 

    def __delitem__(self, idx): 
     del self._refs[idx] 

    def append(self, obj): 
     self._refs.append(weakref.ref(obj, self._mark_dirty)) 

    def count(self, obj): 
     return list(self).count(obj) 

    def extend(self, items): 
     for x in items: self.append(x) 

    def index(self, obj): 
     return list(self).index(obj) 

    def insert(self, idx, obj): 
     self._refs.insert(idx, weakref.ref(obj, self._mark_dirty)) 

    def pop(self, idx): 
     if self._dirty: self.flush() 
     obj=self._refs[idx]() 
     del self._refs[idx] 
     return obj 

    def remove(self, obj): 
     if self._dirty: self.flush() # Ensure all valid. 
     for i, x in enumerate(self): 
      if x == obj: 
       del self[i] 

    def reverse(self): 
     self._refs.reverse() 

    def sort(self, cmp=None, key=None, reverse=False): 
     if self._dirty: self.flush() 
     if key is not None: 
      key = lambda x,key=key: key(x()) 
     else: 
      key = apply 
     self._refs.sort(cmp=cmp, key=key, reverse=reverse) 

    def __add__(self, other): 
     l = WeakList(self) 
     l.extend(other) 
     return l 

    def __iadd__(self, other): 
     self.extend(other) 
     return self 

    def __contains__(self, obj): 
     return obj in list(self) 

    def __mul__(self, n): 
     return WeakList(list(self)*n) 

    def __imul__(self, n): 
     self._refs *= n 
     return self 

[編集]より完全なリストの実装を追加

+0

繰り返し中にリストのサイズが変化した場合、どのように動作しますか?私は '__iter__'と' remove'のループについて話しています。 – Niriel

1

なぜあなたはちょうどこのようにそれを行うことはできません:。extendなど作品を私のため 、

import weakref 

class WeakList(list): 
    def append(self, item): 
     list.append(self, weakref.ref(item, self.remove)) 

をそして__iadd__のために同様のやる

+1

うーん...それは動作しません。私はPython 2.6と3.1でチェックし、第2引数をサポートしていませんでした。TypeError:append()は1つの引数(2が与えられました)をとります。 –

+0

スーパー(リスト、自己).appendなど –

+0

@Mu Mind: – user508402

5

WeakSetは、同じweakrefモジュールから使用できます(実際には別のところで定義されていますが、インポートされています)。

>>> from weakref import WeakSet 
>>> s = WeakSet() 
>>> class Obj(object): pass # can't weakref simple objects 
>>> a = Obj() 
>>> s.add(a) 
>>> print len(s) 
1 
>>> del a 
>>> print len(s) 
0 
+3

WeakSetはハッシュ可能オブジェクトのみを格納できます。 –

+4

また、エントリの順序を保持しないという欠点もあります。 – SingleNegationElimination

+2

@PeterGrahamとTokenMacGuy:OPには注文に関する要件が記載されていませんでした。だから、彼がちょうど弱い妖精のものの[順序付けられていない]バッグを望んでいて、それらのものがハッシュ可能であれば、WeakSetの考え方は実行可能に見えます。物事が彼自身のデザインの対象であれば、おそらく彼は自分自身のオブジェクトでハッシュ可能な要件を満たすことができます。 –

0

Bをどのように使用する予定ですか?その実装は簡単ですので、私が今まで私が建てweakrefリストで行う唯一のものは、それを反復さ:

import weakref 

class WeakRefList(object): 
    "weakref psuedo list" 
    def __init__(yo): 
     yo._items = list() 
    def __iter__(yo): 
     yo._items = [s for s in yo._items if s() is not None] 
     return (s() for s in yo._items if s() is not None) 
    def __len__(yo): 
     yo._items = [s for s in yo._items if s() is not None] 
     return len(yo._items) 
    def append(yo, new_item): 
     yo._items.append(weakref.ref(new_item)) 
     yo._items = [s for s in yo._items if s() is not None] 
2

weakrefの第2引数に渡されたコールバック関数を使用します。このコードは機能するはず

import weakref 

class weakRefList(list): 

    def addReference(self, obj): 
     self._references.append(weakref.proxy(obj, self.remove)) 
5

を私はあなたのようなweakrefリストを必要に応じて、私は1つを作ったとは、PyPI上でそれを公開しました。

今あなたが行うことができます:

pip install weakreflist 

その後:

from weakreflist import WeakList