- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
Python 3.2 的 weakref
模块的 WeakKeyDictionary
和 WeakValueDictionary
的文档有关于迭代这些的说明容器:
Note: Caution: Because a WeakKeyDictionary is built on top of a Python dictionary, it must not change size when iterating over it. This can be difficult to ensure for a WeakKeyDictionary because actions performed by the program during iteration may cause items in the dictionary to vanish “by magic” (as a side effect of garbage collection).
作为这些容器行为的规范,这似乎相当可怕。尤其是在运行使用 CPython 垃圾收集器的代码(使用包含循环的数据结构时)或使用其他 Python 实现(例如 Jython)时,听起来好像没有安全的方法来迭代这些集合。
当垃圾收集器可能在我的程序中的任何时候清除引用时,我如何安全地迭代这些集合?为 CPython 提供解决方案是我的首要任务,但我也对其他实现的问题感兴趣。
这可能是一种遍历 WeakKeyDictionary 的安全方法吗?
import weakref
d = weakref.WeakKeyDictionary()
...
for k, v in list(d.items()):
...
最佳答案
在 Python 2.7 或 Python 3.1+ 中迭代 WeakKeyDictionary
、WeakValueDictionary
或 WeakSet
实际上是安全的。 They put in an iteration guard这可以防止 weakref 回调从底层 dict 中删除引用或在 2010 年的迭代期间设置,但文档从未更新过。
有了守卫,如果一个条目在迭代到达它之前死亡,迭代将跳过该条目,但它不会导致段错误或运行时错误或任何东西。死条目将被添加到待删除列表中并在以后处理。
Here's the guard (不是线程安全的,尽管有评论):
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()
Here's where the WeakKeyDictionary weakref callback checks the guard :
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]
And here's where WeakKeyDictionary.__iter__
sets the guard :
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
会返回一个列表,它会使用底层字典的 items
方法,该方法(大部分?)不会被 GC 中断。 3.0 中的 dict API 更改改变了 keys
/values
/items
的工作方式,这可能就是引入守卫的原因。
关于python - 安全地迭代 WeakKeyDictionary 和 WeakValueDictionary,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12428026/
是否有任何方法可以解决 WeakValueDictionary 的限制,使其能够保存对 dict 或 list 等内置类型的弱引用?可以在扩展模块中的 C 级别完成某些操作吗?我真的需要一个可以容纳(
>>> from weakref import WeakValueDictionary >>> class Foo(object): ... pass >>> foo = Foo() >>>
我正在尝试下载freyface数据集并展示它的一些示例。 这是我的代码: import numpy as np import matplotlib.pyplot as plt # configure
Python 3.2 的 weakref 模块的 WeakKeyDictionary 和 WeakValueDictionary 的文档有关于迭代这些的说明容器: Note: Caution: Bec
根据 weakref 模块的官方 Python 文档,“弱引用的主要用途是实现包含大对象的缓存或映射,...”。因此,我使用 WeakValueDictionary 为长时间运行的函数实现缓存机制
我试图理解 Python weakref 模块及其用例,所以我有以下设置: import gc, weakref class obj(object): def __init__(self, v
我是一名优秀的程序员,十分优秀!