如何创建元组的循环引用?

由于历史原因(阅读:可怕的type(t) == tuple检查),我发现自己需要冻结圆形图作为tuple对象的集合。显然,这并不理想:

>>> head = ("head",None)
>>> a = ("a",("b",("c",head)))
>>> head[1] = a
Traceback (most recent call last):
  File "<pyshell#3>",line 1,in <module>
    head[1] = a
TypeError: 'tuple' object does not support item assignment

但是,我并不是TypeError的真正信奉者,并且怀疑通过特定于实现的黑客手段可以做到这一点。

  • 我如何产生这种怪异而又不冒险超出界限或引起其他C不确定行为?
  • 垃圾回收器的循环依赖释放部分可以应付这种情况吗?
etreg 回答:如何创建元组的循环引用?

  

但是,我并不是TypeErrors的真正拥护者,并且怀疑通过特定于实现的黑客,可以做到这一点。

可悲的是,您是正确的:

from ctypes import Structure,c_ssize_t,c_void_p,py_object,pythonapi

pythonapi.Py_DecRef.argtypes = py_object,def mutable(tup):
    # We are generating this class dynamically because the size of ob_item
    # varies according to the size of the given tuple
    class PyTupleObject(Structure):
        _fields_ = [('ob_refcnt',c_ssize_t),('ob_type',c_void_p),('ob_size',('ob_item',py_object * len(tup))]

        @classmethod
        def from_tuple(cls,tup):
            instance = cls.from_address(id(tup))
            # Save a reference to tup on the instance,as we are using it directly from memory
            # and don't want it to be garbage collected
            instance.original = tup
            return instance

        def __setitem__(self,idx,val):
            # Replacing a value in self.ob_item doesn't decref the old value but does indref the new value
            pythonapi.Py_DecRef(self.ob_item[idx])
            self.ob_item[idx] = val

        def __getitem__(self,idx):
            return self.ob_item[idx]

        def __iter__(self):
            return iter(self.ob_item)

        def __len__(self):
            return len(self.ob_item)

        def __contains__(self,val):
            return val in self.ob_item

    return PyTupleObject.from_tuple(tup)


if __name__ == '__main__':
    tup = (None,)
    mut_tup = mutable(tup)
    mut_tup[0] = tup
    print(tup is tup[0]) # Outputs "True"
  

如何产生这种怪异而又不会冒出界外或引起其他C不确定行为的危险?

我们通过将成员ob_item定义为py_object * len(tup)来防止越界访问。

  

垃圾回收器的循环依赖释放部分可以应付这种情况吗?

不!元组应该是不可变的,因此不希望对其具有循环引用。这就是为什么他们不实现tp_clear方法的原因,Python垃圾回收器使用该方法来中断参考周期并收集涉及的垃圾。更多详细信息here

本文链接:https://www.f2er.com/3131420.html

大家都在问