python中修改局部json的思路
背景
希望修改某个路径下的字段,但是不希望覆盖其他字段。
{
"name": "张三",
"age": 18
}
类似于上下对比这样。
{
"name": "张三",
"age": 21
}
方案
get - set
使用get获取整个对象,然后修改整个对象后使用set。
回调函数
def callback(obj):
obj['age'] = 21
return obj
隔应的地方有两点:
- python的匿名函数只能有一条表达式,因此即使是上面这种简单的语句也得写一个具名函数,非常啰嗦。
- 事实上在执行
obj['age'] = 21的时候值的修改已经完成(对象的话),但是考虑到还有字符串等简单数值,因此还是有返回值,并且内部有赋值操作。因此如果是对象的话,会有一次无效的赋值。(类似于obj=obj)
总的来说,完全没有简洁性可言。
pydash

比较完美地解决了问题,但是我不希望这种小问题都引入一个库。
自设计路径
仅仅是思路,因此直接使用ai代码做示例。
import json
from pathlib import Path
from datetime import datetime
def update_json_field_by_path(file_path: str, indices_and_keys: list, new_value: any) -> bool:
"""
通过指定索引和键的路径,安全地修改 JSON 文件中的值。
Args:
file_path: JSON 文件的路径。
indices_and_keys: 从根到目标字段的路径列表。
例如: ["hika", "latest_login"] 或 [0, "hika", "latest_login"]
new_value: 要写入的新值。
Returns:
bool: 如果成功找到并更新了字段,返回 True;否则返回 False。
"""
file = Path(file_path)
# --- 1. 读取数据 ---
try:
if not file.exists():
print(f"错误:文件不存在于路径 '{file_path}'")
return False
with open(file, 'r', encoding='utf-8') as f:
data = json.load(f)
except Exception as e:
print(f"读取或解析 JSON 文件时发生错误: {e}")
return False
# --- 2. 遍历路径找到目标字段 ---
current_level = data
path_trace = []
try:
# 遍历路径列表,直到倒数第二个元素 (即目标字段的父级)
for i, key_or_index in enumerate(indices_and_keys[:-1]):
path_trace.append(str(key_or_index))
# 检查当前级别是否包含下一个键/索引
if isinstance(current_level, list):
# 如果是列表,期望 key_or_index 是整数索引
current_level = current_level[int(key_or_index)]
elif isinstance(current_level, dict):
# 如果是字典,期望 key_or_index 是字符串键
current_level = current_level[str(key_or_index)]
else:
raise TypeError(f"路径错误:'{key_or_index}' 无法应用于 {type(current_level).__name__} 类型。路径终止于:{' -> '.join(path_trace)}")
# 最终的键/字段名是路径列表的最后一个元素
final_key = indices_and_keys[-1]
# --- 3. 修改目标字段 ---
if isinstance(current_level, dict) and str(final_key) in current_level:
# 这一步是关键:只修改了内存中 data 变量的深层嵌套字段
current_level[str(final_key)] = new_value
print(f"字段路径 {' -> '.join(path_trace + [str(final_key)])} 已更新为: {new_value}")
else:
print(f"错误:无法在路径 {' -> '.join(path_trace)} 中找到字段 '{final_key}' 或目标不是字典。")
return False
except (IndexError, KeyError, TypeError, ValueError) as e:
print(f"错误:无效的路径或结构不匹配。详细错误: {e}")
return False
# --- 4. 写入数据 (覆盖原文件) ---
try:
with open(file, 'w', encoding='utf-8') as f:
# 使用 indent=4 保持文件格式美观
json.dump(data, f, indent=4, ensure_ascii=False)
return True
except Exception as e:
print(f"写入文件时发生错误: {e}")
return False
# ----------------------------------------------------
# 演示使用
# ----------------------------------------------------
USER_FILE = "users.json"
# 使用当前时间作为新值
current_time = datetime.now().isoformat(timespec='seconds')
# --- 运行示例 ---
# 1. 初始化文件 (请确保文件结构与示例假设一致)
initial_data = [
{"hika": {"latest_login": "", "email": "h.nagi@example.com"}, "id": 1},
{"xxgal": {"latest_login": "", "email": "x.gal@example.com"}, "id": 2}
]
with open(USER_FILE, 'w', encoding='utf-8') as f:
json.dump(initial_data, f, indent=4)
print("--- 原始文件内容 ---")
print(open(USER_FILE, 'r', encoding='utf-8').read())
print("--------------------")
# 目标:修改 data[0]['hika']['latest_login']
path_to_modify = [0, "hika", "latest_login"]
update_successful = update_json_field_by_path(USER_FILE, path_to_modify, current_time)
if update_successful:
print("\n--- 更新后的文件内容 (验证是否只修改了目标字段) ---")
print(open(USER_FILE, 'r', encoding='utf-8').read())
print("-------------------------------------------------------")
结论
折腾来折腾去,还不如直接获取然后修改。看上去不简洁的方法,反而变成了最简洁的方法。

浙公网安备 33010602011771号