При загрузке данных YAML с помощью ruamel.yaml якоря и их псевдонимы в файле YAML являются одним и тем же объектом в Python:
from ruamel.yaml import YAML
yaml_str = """\
first: &reference [1, 2, 3]
second: *reference
"""
yaml = YAML()
data = yaml.load(yaml_str)
assert(data['first'] is data['second'])
# passes
data['first'].append(4)
print(data['second'])
# output: [1, 2, 3, 4]
Я понимаю, что это преднамеренная функция. Однако есть ли способ сказать load
вместо этого копировать псевдонимы, когда он их находит? Я попытался переопределить yaml.representer.ignore_aliases
, как указано в этом ответе, но это только для записи в YAML, а не для чтения из него.
Нет встроенной функциональности, чтобы делать то, что вы хотите. Каждый раз, когда вы сталкиваетесь псевдоним, вам пришлось бы рекурсивно создавать структуру узла в композиторе, а не просто возвращать узел привязки для псевдонима.
Потребность в якорях и псевдонимах в документах YAML возникает из-за необходимости иметь возможность для представления рекурсивных структур данных:
a = [1, 2]
a.append(a)
Вышеупомянутая структура не может быть сброшена с использованием метода, показанного в ответе, на который вы ссылаетесь, и также не может быть представлено в виде документа YAML без расширения:
&id001
- 1
- 2
- *id001
расширяться во время загрузки по методике, предложенной в первом абзаце.
Ваш (нерекурсивный) пример можно сбросить с помощью техники в связанном ответе, и его также можно было расширить во время загрузки.
Самое простое решение, если вы не хотите погрузиться в недра ruamel.yaml, это загрузите документ YAML, дамп с расширением, а затем загрузите результат дампа:
import sys
import ruamel.yaml
yaml_str = """\
first: &reference [1, 2, 3]
second: *reference
"""
yaml = ruamel.yaml.YAML()
yaml.representer.ignore_aliases = lambda *data: True
data = yaml.load(yaml_str)
buf = ruamel.yaml.compat.BytesIO()
out = yaml.dump(data, buf)
data = yaml.load(buf.getvalue())
assert(data['first'] is not data['second'])
assert(data['first'] == data['second'])
data['first'].append(4)
assert len(data['first']) == 4
assert len(data['second']) == 3
Конечно, это не очень эффективно, когда у вас огромный файл.