正如我们(或至少我)在 this answer 中学到的那样,python 的垃圾收集器不会跟踪仅包含不可变值的简单元组,一旦发现它们永远不会参与引用循环:

>>> import gc
>>> x = (1, 2)
>>> gc.is_tracked(x)
True
>>> gc.collect()
0
>>> gc.is_tracked(x)
False

为什么 namedtuple 不是这种情况,它是 collections 模块中具有命名字段的 tuple 的子类?
>>> import gc
>>> from collections import namedtuple
>>> foo = namedtuple('foo', ['x', 'y'])
>>> x = foo(1, 2)
>>> gc.is_tracked(x)
True
>>> gc.collect()
0
>>> gc.is_tracked(x)
True

他们的实现中是否有一些固有的东西可以防止这种情况,或者只是被忽视了?

最佳答案

我能找到的关于此的唯一评论是在 Python 源代码的 gcmodule.c 文件中:



(请参阅链接的问题以查看为允许取消跟踪而引入的真实代码)

这个评论有点含糊,但它没有说明选择“取消跟踪”哪个对象的算法适用于通用容器。这意味着代码只检查 tuple s(和 dict s),而不是它们的子类。

您可以在文件的代码中看到这一点:

/* Try to untrack all currently tracked dictionaries */
static void
untrack_dicts(PyGC_Head *head)
{
    PyGC_Head *next, *gc = head->gc.gc_next;
    while (gc != head) {
        PyObject *op = FROM_GC(gc);
        next = gc->gc.gc_next;
        if (PyDict_CheckExact(op))
            _PyDict_MaybeUntrack(op);
        gc = next;
    }
}

注意对 PyDict_CheckExact 的调用,以及:
static void
move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
{
    PyGC_Head *gc = young->gc.gc_next;

  /* omissis */
            if (PyTuple_CheckExact(op)) {
                _PyTuple_MaybeUntrack(op);
            }

请注意对 PyTuple_CheckExact 的调用。

另请注意,tuple 的子类不必是不可变的。这意味着如果你想在 tupledict 之外扩展这个机制,你需要一个通用的 is_immutable 函数。这将非常昂贵,如果可能的话,由于 Python 的动态性(例如,类的方法可能会在运行时更改,而这对于 tuple 来说是不可能的,因为它是内置类型)。因此,开发人员选择坚持少数特殊情况,仅使用一些知名的内置插件。

这就是说,我相信他们也可以对 namedtuple 进行特殊处理,因为它们是非常简单的类。例如,当您调用 namedtuple 时会出现一些问题,您正在创建一个新类,因此 GC 应该检查子类。
这可能是代码的问题,例如:
class MyTuple(namedtuple('A', 'a b')):
    # whatever code you want
    pass

因为 MyTuple 类不需要是不可变的,所以为了安全起见,GC 应该检查该类是否是 namedtuple 的直接子类。但是,我很确定有针对这种情况的解决方法。

他们可能没有,因为 namedtuple 是标准库的一部分,而不是 python 核心。也许开发人员不想让核心依赖于标准库的模块。

所以,回答你的问题:
  • 不,他们的实现中没有任何内容可以阻止对 namedtuple s
  • 的取消跟踪
  • 不,我相信他们并没有“简单地忽略”这一点。然而,只有 python 开发人员可以明确回答为什么他们选择不包括它们。我的猜测是他们认为这不会为更改提供足够大的好处,并且他们不想让核心依赖于标准库。
  • 关于python - 为什么命名元组总是被python的GC跟踪?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/19770515/

    10-12 20:56
    查看更多