我需要一个弱引用列表,它们会在项目死亡时删除它们.目前,我这样做的唯一方法是不断刷新列表(手动删除死引用).
我知道有一个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()
Brian.. 6
你可以自己实现它,类似于你的工作方式,但是在尝试访问项目之前使用一个调用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
[编辑]添加更完整的列表实现.
你可以自己实现它,类似于你的工作方式,但是在尝试访问项目之前使用一个调用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
[编辑]添加更完整的列表实现.
您可以使用来自同一个weakref模块的WeakSet(它实际上是在其他地方定义的,但它是在那里导入的).
>>> 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
因为我需要像你这样的弱列表,我已经制作了一个并在pypi上发布它.
现在你可以这样做:
pip install weakreflist
然后:
from weakreflist import WeakList