Я открываю этот вопрос по запросу от автора ruamel.yaml на Как изменить привязанный скаляр в последовательности, не разрушая якорь в ruamel.yaml? .
В ответе https://stackoverflow.com/a/55717146/5880190, был дан следующий код для решения вопроса о том, как обновить псевдонимы значений в данных ruamel.yaml:
def update_aliased_scalar(data, obj, val):
def recurse(d, ref, nv):
if isinstance(d, dict):
for i, k in [(idx, key) for idx, key in enumerate(d.keys()) if key is ref]:
d.insert(i, nv, d.pop(k))
for k, v in d.non_merged_items():
if v is ref:
d[k] = nv
else:
recurse(v, ref, nv)
elif isinstance(d, list):
for idx, item in enumerate(d):
if item is ref:
d[idx] = nv
else:
recurse(item, ref, nv)
if hasattr(obj, 'anchor'):
recurse(data, obj, type(obj)(val, anchor=obj.anchor.value))
else:
recurse(data, obj, type(obj)(val))
Этот блестящий код работал такхорошо, что я обернул его в функцию и использовал в своем проекте для обработки выполнения всех изменений данных, как показано здесь (с легким переименованием, чтобы соответствовать стилю кода, в который он был вставлен): https://github.com/wwkimball/yamlpath/blob/319585620abfab199f3e15c87e0a2dc2c900aa1d/yamlpath/processor.py#L739-L781
Это сработало очень хорошо для большинства случаев использования моего проекта.Я использую этот код с большим успехом в производстве с тех пор.Значения, с которыми я работаю, - это почти исключительно строковые данные, и случайно любые нестроковые данные оказываются псевдонимами, потому что обычно используются номера портов службы.
На основании этих успехов, а не при критическом чтении кода (Я полностью доверяю автору, который знает ruamel.yaml гораздо лучше меня), я ошибочно полагал, что этот код обновляет только целевой узел и любые ссылки на it .Поэтому я также подумал, что этот код можно использовать для обновления данных без псевдонимов.Я ошибался.Это моя ошибка.
Как оказалось, всякий раз, когда для обновления этой функции передается не строковое значение, он заменяет не только этот целевой узел, но каждый узел наодно и то же значение, даже если они не являются ссылками друг на друга .Таким образом, когда данные выглядят следующим образом:
---
key: 42
other_key: 42
Вызов функции для изменения key: 42
на key: 5280
не только вносит ожидаемое изменение, но также меняет other_key:
на 5280
.Это не происходит , когда изменяемое значение представляет собой строковые данные без псевдонима, независимо от того, сколько других узлов имеют такое же значение (что заставило меня поверить, что это безопасноиспользуйте эту функцию для обновления любого значения , с псевдонимом или без него).Это действительно также происходит, когда значения булевы.
Я не понял, что на самом деле делал код.Я использовал код способом, для которого он не был предназначен.
Мне нужна функция, которая принимает узел для изменения, а затем изменяет только этот узел, когда он являетсязначение без псевдонима и , если оно является значением с псевдонимом, также измените все остальные узлы с псевдонимом без , влияя на другие узлы, которые являются не связанными псевдонимами (* alias1 по сравнению с* alias2) с тем же значением или значениями без псевдонимов, которые совпадают с обновляемым псевдонимом. Когда я вызываю функцию, у меня есть только все данные, целевой узел иожидаемое новое значение для него.
Я открыт для рефакторинга своего собственного кода, если функция требует больше информации при вызове.