如何创建元组的循环引用?
How can I create a circular reference of tuples?
出于历史原因(阅读:可怕的 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 未定义行为的风险的情况下产生这种怪物?
- 垃圾收集器的循环依赖释放部分能应付这样的事情吗?
I, however, am not really a great believer in TypeErrors, and suspect that, through implementation-specific hackery, this can be done.
遗憾的是,你是对的:
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', c_ssize_t),
('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"
How can I produce this monstrosity without risking going Out of Bounds or causing other C Undefined Behaviour?
我们通过将成员 ob_item
定义为 py_object * len(tup)
.
来防止越界访问
Can the circular dependency freeing part of the Garbage Collector cope with such a thing?
没有!元组应该是不可变的,因此不希望对它们自己有循环引用。这就是为什么他们没有实现 tp_clear
方法,python 垃圾收集器使用该方法来打破引用循环并收集所涉及的垃圾。更多详情 here
出于历史原因(阅读:可怕的 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 未定义行为的风险的情况下产生这种怪物?
- 垃圾收集器的循环依赖释放部分能应付这样的事情吗?
I, however, am not really a great believer in TypeErrors, and suspect that, through implementation-specific hackery, this can be done.
遗憾的是,你是对的:
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', c_ssize_t),
('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"
How can I produce this monstrosity without risking going Out of Bounds or causing other C Undefined Behaviour?
我们通过将成员 ob_item
定义为 py_object * len(tup)
.
Can the circular dependency freeing part of the Garbage Collector cope with such a thing?
没有!元组应该是不可变的,因此不希望对它们自己有循环引用。这就是为什么他们没有实现 tp_clear
方法,python 垃圾收集器使用该方法来打破引用循环并收集所涉及的垃圾。更多详情 here