You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

含自定义对象的大文件转Python字典内存及JSON序列化问题

解决大体积自定义格式数据解析的问题

针对你遇到的eval内存溢出、JSON序列化失败以及大文件打印缓慢的问题,给出以下实用方案:

1. 替换eval,用安全高效的ast.literal_eval解析

eval会执行任意代码,且处理大文件时会一次性加载所有内容并创建大量中间对象,导致内存暴涨。改用ast.literal_eval更安全,内存效率也更高,但需要先把自定义类型转成Python原生字面量:

import ast
import re

with open('transpostion.txt', 'r') as f:
    raw_data = f.read()
    # 把Cp(+57)转成('Cp', 57)格式
    raw_data = re.sub(r'Cp\(([+-]\d+)\)', r"('Cp', \1)", raw_data)
    # 把PovScore(Cp(...), BLACK)转成('PovScore', ('Cp', 57), 'BLACK')
    raw_data = re.sub(r'PovScore\((.*?), (BLACK|WHITE)\)', r"('PovScore', \1, \2)", raw_data)
    # 把BLACK/WHITE转成字符串字面量
    raw_data = raw_data.replace('BLACK', "'BLACK'").replace('WHITE', "'WHITE'")
    # 解析为字典
    data_dict = ast.literal_eval(raw_data)

解析完成后,你可以遍历字典,把元组重新转换回PovScore和Cp对象。

2. 让JSON支持自定义对象序列化/反序列化

JSON默认不支持自定义类对象,需要自定义编码器和解码器来处理PovScore、Cp和BLACK/WHITE:

序列化(保存数据时用)

import json

class ChessScoreEncoder(json.JSONEncoder):
    def default(self, obj):
        # 处理PovScore对象
        if isinstance(obj, PovScore):
            return {
                '__type__': 'PovScore',
                'cp': obj.cp,  # 假设PovScore有cp属性存储Cp对象
                'color': obj.color  # 假设color是BLACK/WHITE枚举
            }
        # 处理Cp对象
        elif isinstance(obj, Cp):
            return {
                '__type__': 'Cp',
                'value': obj.value  # 假设Cp有value属性存储分数
            }
        # 处理BLACK/WHITE枚举
        elif obj in (BLACK, WHITE):
            return obj.name  # 假设枚举有name属性,比如BLACK.name = 'BLACK'
        # 其他类型用默认处理
        return super().default(obj)

# 保存为JSON文件
with open('transpostion.json', 'w') as f:
    json.dump(data_dict, f, cls=ChessScoreEncoder, indent=2)

反序列化(读取JSON文件时用)

def chess_score_decoder(obj):
    if '__type__' in obj:
        # 还原PovScore对象
        if obj['__type__'] == 'PovScore':
            cp_obj = Cp(obj['cp']['value'])
            return PovScore(cp_obj, obj['color'])
        # 还原Cp对象
        elif obj['__type__'] == 'Cp':
            return Cp(obj['value'])
        # 还原BLACK/WHITE枚举
        elif obj['__type__'] == 'BLACK':
            return BLACK
        elif obj['__type__'] == 'WHITE':
            return WHITE
    return obj

# 读取JSON文件
with open('transpostion.json', 'r') as f:
    data_dict = json.load(f, object_hook=chess_score_decoder)

3. 优化大文件读取与打印

  • 逐行读取大文件:避免一次性加载全部内容到内存,减轻内存压力:
import ast
import re

# 匹配每一行的键值对
line_pattern = re.compile(r"'(0x[0-9a-f]+)': \[(.*?), (\d+)\]")
data_dict = {}

with open('transpostion.txt', 'r') as f:
    for line in f:
        line = line.strip().rstrip(',').strip()
        if not line:
            continue
        match = line_pattern.match(line)
        if match:
            key = match.group(1)
            score_raw = match.group(2)
            num = int(match.group(3))
            # 处理分数部分为字面量
            score_raw = re.sub(r'Cp\(([+-]\d+)\)', r"('Cp', \1)", score_raw)
            score_raw = re.sub(r'PovScore\((.*?), (BLACK|WHITE)\)', r"('PovScore', \1, \2)", score_raw)
            score_raw = score_raw.replace('BLACK', "'BLACK'").replace('WHITE', "'WHITE'")
            score = ast.literal_eval(score_raw)
            data_dict[key] = [score, num]
  • 分批打印大字典:直接打印整个大字典会导致IDLE卡顿,只打印部分关键信息:
# 打印前10条数据
for idx, (key, value) in enumerate(data_dict.items()):
    if idx >= 10:
        break
    print(f"{key}: {value}")
# 打印总条数
print(f"... 总计 {len(data_dict)} 条数据")

内容的提问来源于stack exchange,提问作者winapiadmin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 13:28:36