这是在实际安全的迭代WeakKeyDictionary
,WeakValueDictionary
或WeakSet
在Python 2.7或Python 3.1+。他们引入了一个迭代保护措施,以防止弱引用回调从2010年以来的迭代过程中从底层dict或集合中删除引用,但是这些文档从未得到更新。
有了警惕,如果一个条目在迭代到达之前就死了,那么迭代将跳过该条目,但是不会导致segfault或RuntimeError或任何其他错误。无效条目将添加到挂起的删除列表中,并在以后处理。
class _IterationGuard:
# This context manager registers itself in the current iterators of the
# weak container, such as to delay all removals until the context manager
# exits.
# This technique should be relatively thread-safe (since sets are).
def __init__(self, weakcontainer):
# Don't create cycles
self.weakcontainer = ref(weakcontainer)
def __enter__(self):
w = self.weakcontainer()
if w is not None:
w._iterating.add(self)
return self
def __exit__(self, e, t, b):
w = self.weakcontainer()
if w is not None:
s = w._iterating
s.remove(self)
if not s:
w._commit_removals()
这是WeakKeyDictionary弱引用回调检查防护的地方:
def remove(k, selfref=ref(self)):
self = selfref()
if self is not None:
if self._iterating:
self._pending_removals.append(k)
else:
del self.data[k]
这是WeakKeyDictionary.__iter__
设置警卫的地方:
def keys(self):
with _IterationGuard(self):
for wr in self.data:
obj = wr()
if obj is not None:
yield obj
__iter__ = keys
在其他迭代器中使用相同的防护。
如果没有这个守卫,打电话list(d.items())
也不安全。GC遍历可能发生在items
迭代器内部,并在迭代过程中从dict中删除项目。(list
用C语言编写的事实不会提供任何保护。)
在2.6和更早的版本中,迭代WeakKeyDictionary或WeakValueDictionary的最安全方法是使用items
。items
会返回一个列表,并使用底层dict的items
方法,该方法通常不会被GC中断(主要是?)。在3.0的字典API的变化而变化如何keys
/values
/items
工作,这可能是为什么警卫被引入时,它是。