Python解析JSON/XML时,对重复键是否执行字符串驻留以节省内存?
问题解答:反序列化大型字典数组时Python是否会对重复键做字符串驻留
核心结论
默认情况下,Python标准库的JSON/XML解析器不会主动对字典的重复键执行字符串驻留优化,但可以通过手动方式实现内存节省。
1. JSON模块(json.load/json.loads)的表现
- 默认行为:解析过程中,每个字典键都会生成独立的字符串对象——哪怕1000个字典都用
"name"作为键,默认也会创建1000个互不关联的"name"字符串实例。这是因为json模块优先保证解析速度,未内置键的驻留逻辑。 - 手动优化方案:借助
sys.intern()和自定义解析钩子,强制重复键共享同一字符串对象。示例代码:
import json import sys def intern_dict_keys(obj): if isinstance(obj, dict): # 对每个键执行驻留,递归处理值 return {sys.intern(k): intern_dict_keys(v) for k, v in obj.items()} elif isinstance(obj, list): return [intern_dict_keys(item) for item in obj] else: return obj # 加载时应用钩子 with open("large_dataset.json", "r") as f: data = json.load(f, object_hook=intern_dict_keys)
2. xml.dom.minidom的表现
- 默认行为:解析XML后,元素标签名、属性名这类类似“键”的字符串,同样不会自动驻留。相同的标签/属性名会生成多个独立字符串实例。
- 手动优化方案:遍历DOM树,用
sys.intern()处理所有标签和属性名:
import xml.dom.minidom import sys def intern_dom_nodes(node): if node.nodeType == node.ELEMENT_NODE: # 驻留标签名 node.tagName = sys.intern(node.tagName) # 驻留属性名 processed_attrs = {} for attr_name, attr_val in node.attributes.items(): processed_attrs[sys.intern(attr_name)] = attr_val node.attributes = processed_attrs # 递归处理子节点 for child in node.childNodes: intern_dom_nodes(child) # 解析后执行驻留处理 dom = xml.dom.minidom.parse("large_dataset.xml") intern_dom_nodes(dom)
3. 关于Python字符串驻留的补充
Python解释器本身会对**代码中的字面量小字符串(通常长度<20)**自动驻留,但反序列化时生成的字符串是动态创建的,不在这个自动优化范围内。sys.intern()是手动触发驻留的可靠方式,它会将字符串存入全局驻留池,后续相同字符串会直接返回已有对象的引用。
内容的提问来源于stack exchange,提问作者Vadim Kantorov
相关产品推荐
相关产品推荐

