我需要一个弱引用列表,用于在项死亡时将其删除。目前,我唯一能做到这一点的方法就是不断刷新列表(手动删除无效引用)。
我知道有一个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()
发布于 2009-03-25 01:08:37
您可以自己实现它,类似于您所做的操作,但是使用一个list子类,它在尝试访问一个项之前调用flush()。
显然,您不希望在每次访问时都这样做,但您可以通过在弱引用上设置回调来优化这一点,以便在某些东西死掉时将列表标记为脏的。然后,您只需在自上次访问以来某些内容已死时刷新列表。
下面是一个使用此方法实现的list类。(请注意,它没有经过太多的测试,而且一些方法的实现效率不是很高。那些只是转换为真实列表并调用该列表上的方法的列表),但这应该是一个合理的起点:
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
编辑添加更完整的列表实现。
发布于 2011-06-08 06:52:26
您可以从完全相同的弱引用模块使用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
发布于 2012-11-21 13:06:20
因为我需要一个像你这样的弱引用列表,所以我做了一个,并发布在pypi上。
现在您可以执行以下操作:
pip install weakreflist
然后:
from weakreflist import WeakList
https://stackoverflow.com/questions/677978
复制相似问题