为何JSON文件无法根据depth参数实现层级嵌套缩进?
问题分析与解决方案
问题根源
你当前的代码存在两个核心问题:
- 循环覆盖文件:每次循环都打开
output.json并以写模式覆盖,最终文件只会保留最后一次循环的缩进设置,前面的操作完全无效。 json.dump的indent是全局参数:这个参数控制的是整个JSON结构的基础缩进步长,所有层级都会基于这个值递进(比如indent=4时,第一层4空格,第二层8空格),无法单独为某个子对象设置自定义的缩进深度。
解决方案
标准库的json模块不支持为单个元素设置独立缩进,需要手动实现自定义格式化逻辑。下面提供两种可行方案:
方案1:自定义递归序列化函数
通过递归遍历数据结构,针对submodules中的每个元素使用对应depth值设置缩进:
import os def custom_json_serialize(obj, indent_step=4, depth_map=None, current_list=None): indent = ' ' * indent_step if isinstance(obj, dict): items = [] for key, value in obj.items(): key_str = f'"{key}"' # 递归处理值,层级+1 value_str = custom_json_serialize(value, indent_step, depth_map, current_list) items.append(f'{indent}{key_str}: {value_str}') return '{\n' + ',\n'.join(items) + f'\n{indent[:-indent_step]}}}' elif isinstance(obj, list): elements = [] # 标记当前处理的列表是否是submodules is_submodules = current_list == "submodules" for idx, elem in enumerate(obj): # 如果是submodules列表,使用对应的depth值作为起始缩进层级 start_depth = depth_map[idx] if is_submodules else 1 elem_str = custom_json_serialize(elem, indent_step, depth_map) # 生成对应层级的缩进 elem_indent = ' ' * (start_depth * indent_step) elements.append(f'{elem_indent}{elem_str}') # 列表的外层缩进用顶层层级 outer_indent = indent[:-indent_step] if not is_submodules else '' return '[\n' + ',\n'.join(elements) + f'\n{outer_indent}]' elif isinstance(obj, str): return f'"{obj}"' else: return str(obj) def main(directory_path): submodules, depth = parse_directory(directory_path) output = { "name": os.path.basename(directory_path), "repository": os.path.dirname(os.path.realpath(directory_path)), "submodules": submodules } # 调用自定义序列化函数,传入depth作为submodules的缩进层级映射 json_str = custom_json_serialize(output, depth_map=depth, current_list="submodules") # 手动添加顶层对象的缩进 json_str = json_str.replace('{', '{\n ', 1) with open("output.json", "w") as output_file: output_file.write(json_str)
方案2:先序列化再替换内容
先将整个对象序列化为无缩进的JSON字符串,再针对每个submodule替换为带对应缩进的版本:
import json import os def main(directory_path): submodules, depth = parse_directory(directory_path) output = { "name": os.path.basename(directory_path), "repository": os.path.dirname(os.path.realpath(directory_path)), "submodules": submodules } # 先序列化为无缩进的字符串 raw_json = json.dumps(output, separators=(',', ':')) # 逐个替换submodule为带对应缩进的格式 for submod, d in zip(submodules, depth): # 生成带指定缩进的submodule字符串 indented_submod = json.dumps(submod, indent=d*4) # 生成原始无缩进的submodule字符串用于匹配替换 raw_submod = json.dumps(submod) # 替换(注意:如果存在重复的submodule会替换所有匹配项,需确保submodule唯一) raw_json = raw_json.replace(raw_submod, indented_submod) # 最后给顶层对象添加基础缩进 formatted_json = raw_json.replace('{"name"', '{\n "name"').replace('"submodules":', '\n "submodules":') with open("output.json", "w") as output_file: output_file.write(formatted_json)
注意事项
- 方案2中如果
submodules存在完全相同的元素,会替换所有匹配项,适合元素唯一的场景; - 方案1的自定义序列化逻辑更灵活,可根据实际数据结构调整递归处理规则。
内容的提问来源于stack exchange,提问作者kitchat
相关产品推荐
相关产品推荐

