Python 删除dict、list、tuple中的循环引用
我有下面这段真正的黑客代码,它从由Python 删除dict、list、tuple中的循环引用,python,reference,circular-reference,Python,Reference,Circular Reference,我有下面这段真正的黑客代码,它从由dict、tuple和list对象构建的任何类型的数据结构中删除循环引用 import ast def remove_circular_refs(o): return ast.literal_eval(str(o).replace("{...}", 'None')) 但我不喜欢它有多粗糙。这可以在不将数据结构转换为字符串表示的情况下完成吗 下面是要测试的示例结构: doc1 = { "key": "value", "type": "t
dict
、tuple
和list
对象构建的任何类型的数据结构中删除循环引用
import ast
def remove_circular_refs(o):
return ast.literal_eval(str(o).replace("{...}", 'None'))
但我不喜欢它有多粗糙。这可以在不将数据结构转换为字符串表示的情况下完成吗
下面是要测试的示例结构:
doc1 = {
"key": "value",
"type": "test1",
}
doc1["self"] = doc1
doc = {
'tags': 'Stackoverflow python question',
'type': 'Stackoverflow python question',
}
doc2 = {
'value': 2,
'id': 2,
}
remove_circular_refs(doc)
remove_circular_refs(doc1)
remove_circular_refs(doc2)
不使用字符串转换。只需通过遍历数据结构来检测引用:
def remove_circular_refs(ob, _seen=None):
if _seen is None:
_seen = set()
if id(ob) in _seen:
# circular reference, remove it.
return None
_seen.add(id(ob))
res = ob
if isinstance(ob, dict):
res = {
remove_circular_refs(k, _seen): remove_circular_refs(v, _seen)
for k, v in ob.items()}
elif isinstance(ob, (list, tuple, set, frozenset)):
res = type(ob)(remove_circular_refs(v, _seen) for v in ob)
# remove id again; only *nested* references count
_seen.remove(id(ob))
return res
这包括dict
、list
、tuple
、set
和frozenset
对象;它会记忆看到的每个对象的id()
,当再次看到它时,它将被替换为None
演示:
最后一个测试,对于doc3
,包含共享引用;'string1'
和1
在内存中只存在一次,字典包含对这些对象的多个引用
>>> doc1 = {
... "key": "value",
... "type": "test1",
... }
>>> doc1["self"] = doc1
>>> doc1
{'key': 'value', 'type': 'test1', 'self': {...}}
>>> remove_circular_refs(doc1)
{'key': 'value', 'type': 'test1', 'self': None}
>>> doc2 = {
... 'foo': [],
... }
>>> doc2['foo'].append((doc2,))
>>> doc2
{'foo': [({...},)]}
>>> remove_circular_refs(doc2)
{'foo': [(None,)]}
>>> doc3 = {
... 'foo': 'string 1', 'bar': 'string 1',
... 'ham': 1, 'spam': 1
... }
>>> remove_circular_refs(doc3)
{'foo': 'string 1', 'bar': 'string 1', 'ham': 1, 'spam': 1}