Weakref List In Python
Solution 1:
You could implement it yourself, similarly to how you have done, but with a list subclass that calls flush()
before attempting to access an item.
Obviously you don't want to do this on every access, but you can optimize this by setting a callback on the weak reference to mark the list dirty when something dies. Then you only need to flush the list when something has died since the last access.
Here's a list class implemented using this method. (Note that it's not tested much, and some methods aren't implemented very efficiently (eg. those which just convert to a real list and call the method on that), but it should be a reasonable starting point:
import weakref
classWeakList(list):
def__init__(self, seq=()):
list.__init__(self)
self._refs = []
self._dirty=Falsefor x in seq: self.append(x)
def_mark_dirty(self, wref):
self._dirty = Truedefflush(self):
self._refs = [x for x in self._refs if x() isnotNone]
self._dirty=Falsedef__getitem__(self, idx):
if self._dirty: self.flush()
return self._refs[idx]()
def__iter__(self):
for ref in self._refs:
obj = ref()
if obj isnotNone: yield obj
def__repr__(self):
return"WeakList(%r)" % list(self)
def__len__(self):
if self._dirty: self.flush()
returnlen(self._refs)
def__setitem__(self, idx, obj):
ifisinstance(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]
defappend(self, obj):
self._refs.append(weakref.ref(obj, self._mark_dirty))
defcount(self, obj):
returnlist(self).count(obj)
defextend(self, items):
for x in items: self.append(x)
defindex(self, obj):
returnlist(self).index(obj)
definsert(self, idx, obj):
self._refs.insert(idx, weakref.ref(obj, self._mark_dirty))
defpop(self, idx):
if self._dirty: self.flush()
obj=self._refs[idx]()
del self._refs[idx]
return obj
defremove(self, obj):
if self._dirty: self.flush() # Ensure all valid.for i, x inenumerate(self):
if x == obj:
del self[i]
defreverse(self):
self._refs.reverse()
defsort(self, cmp=None, key=None, reverse=False):
if self._dirty: self.flush()
if key isnotNone:
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 inlist(self)
def__mul__(self, n):
return WeakList(list(self)*n)
def__imul__(self, n):
self._refs *= n
return self
Solution 2:
As I needed a weakref list like you, I've made one and publish it on pypi.
now you can do:
pip install weakreflist
then:
from weakreflist importWeakList
Solution 3:
You can use WeakSet
from the very same weakref module (it's actually defined elsewhere by the way, but it's imported there).
>>>from weakref import WeakSet>>>s = WeakSet()>>>classObj(object): pass# can't weakref simple objects>>>a = Obj()>>>s.add(a)>>>printlen(s)
1
>>>del a>>>printlen(s)
0
Solution 4:
Why can't you just do it like this:
import weakref
classWeakList(list):
defappend(self, item):
list.append(self, weakref.ref(item, self.remove))
And then do similar for __iadd__
, extend
etc.
Works for me.
Solution 5:
How do you plan on using B
? The only thing I ever do with the weakref list I built is iterate over it, so its implementation is simple:
import weakref
classWeakRefList(object):
"weakref psuedo list"def__init__(yo):
yo._items = list()
def__iter__(yo):
yo._items = [s for s in yo._items if s() isnotNone]
return (s() for s in yo._items if s() isnotNone)
def__len__(yo):
yo._items = [s for s in yo._items if s() isnotNone]
returnlen(yo._items)
defappend(yo, new_item):
yo._items.append(weakref.ref(new_item))
yo._items = [s for s in yo._items if s() isnotNone]
Post a Comment for "Weakref List In Python"