如何用Python修改YAML文件中所有'top'键的百分比值?
解决YAML中批量修改"top"百分比值的问题
需求与问题
我需要完成以下操作:
- 加载YAML文件
- 查找所有名为"top"的键
- 提取其百分比格式的值,给数值加5后重新格式化
- 保存修改后的文件
目前编写的代码能找到目标值并计算出新值,但无法通过lookup函数返回的路径修改原始的data变量,请求帮助。
现有代码
import sys from pathlib import Path import ruamel.yaml import re in_file = Path('overview.yaml') out_file = Path('new_overview.yaml') yaml = ruamel.yaml.YAML() data = yaml.load(in_file) #Found this in some other thread def lookup(sk, d, path=[]): # lookup the values for key(s) sk return as list the tuple (path to the value, value) if isinstance(d, dict): for k, v in d.items(): if k == sk: yield (path + [k], v) for res in lookup(sk, v, path + [k]): yield res elif isinstance(d, list): for item in d: for res in lookup(sk, item, path + [item]): yield res #For each found result for path, value in lookup("top", data): #Remove the percentage sign cleanvalue = re.sub('%','', value) #Convert to float and add 5 addvalue = float(cleanvalue) + 5 #Print old and new value print(cleanvalue, addvalue) #with open('husoversigt_changed.yaml', 'wb') as f: # yaml.dump(data, f)
YAML数据示例
type: custom:mod-card card: type: vertical-stack cards: - type: picture-elements elements: - type: state-icon entity: light.zigbee_bedroom_light tap_action: action: more-info style: top: 31% left: 74% - type: state-icon entity: binary_sensor.zigbee_mailbox_on_off tap_action: action: more-info style: top: 3% left: 42% - type: state-icon entity: group.alarm_sensors tap_action: action: more-info style: top: 20% left: 48%
解决方案
问题出在原lookup函数返回的路径中,列表元素被直接加入路径,无法用来定位列表的索引位置。修改lookup函数,让它在遍历列表时记录索引而非元素本身,这样就能通过路径逐层定位到要修改的节点。
修改后的完整代码
import sys from pathlib import Path import ruamel.yaml import re in_file = Path('overview.yaml') out_file = Path('new_overview.yaml') yaml = ruamel.yaml.YAML() data = yaml.load(in_file) def lookup(sk, d, path=[]): # 查找目标键,返回(路径, 值),路径中列表项用索引表示 if isinstance(d, dict): for k, v in d.items(): if k == sk: yield (path + [k], v) yield from lookup(sk, v, path + [k]) elif isinstance(d, list): for idx, item in enumerate(d): yield from lookup(sk, item, path + [idx]) # 遍历所有找到的"top"键 for path, value in lookup("top", data): # 处理数值:移除百分号、加5、重新格式化 clean_value = re.sub('%', '', value) new_num = float(clean_value) + 5 new_value = f"{new_num}%" # 通过路径定位到父节点,修改"top"键的值 parent = data # 遍历路径的前n-1个元素,逐层进入父节点 for key in path[:-1]: parent = parent[key] # 修改目标键的值 parent[path[-1]] = new_value print(f"修改 {value} -> {new_value}") # 保存修改后的文件 with open(out_file, 'wb') as f: yaml.dump(data, f)
关键修改说明
- lookup函数优化:遍历列表时使用
enumerate获取索引idx,将索引加入路径,而非列表元素本身,这样路径中的每个元素都可以作为访问数据的键/索引。 - 路径定位修改:遍历路径的前n-1个元素,逐层进入到目标键的父节点,最后直接修改父节点中的目标键值。
- 值的格式化:计算出新数值后,重新拼接成百分比格式的字符串,确保YAML数据格式正确。
内容的提问来源于stack exchange,提问作者danededane
相关产品推荐
相关产品推荐

