Я читал исходный код PyYAML, чтобы попытаться понять, как определить подходящую конструкторскую функцию, которую я могу добавить с помощью add_constructor
. У меня довольно хорошее представление о том, как работает этот код, но я до сих пор не понимаю, почему конструкторы YAML по умолчанию в SafeConstructor
являются генераторами. Например, метод construct_yaml_map
of SafeConstructor
:
def construct_yaml_map(self, node):
data = {}
yield data
value = self.construct_mapping(node)
data.update(value)
Я понимаю, как генератор используется в BaseConstructor.construct_object
следующим образом, чтобы заглушить объект и только заполнить его данными из node, если deep=False
передано construct_mapping
:
if isinstance(data, types.GeneratorType):
generator = data
data = generator.next()
if self.deep_construct:
for dummy in generator:
pass
else:
self.state_generators.append(generator)
И я понимаю, как данные генерируются в BaseConstructor.construct_document
в случае, когда deep=False
для construct_mapping
.
def construct_document(self, node):
data = self.construct_object(node)
while self.state_generators:
state_generators = self.state_generators
self.state_generators = []
for generator in state_generators:
for dummy in generator:
pass
То, что я не понимаю, состоит в том, что мы удаляем объекты данных и работаем через объекты путем итерации по генераторам в construct_document
. Нужно ли это делать, чтобы что-то поддерживать в спецификации YAML, или это обеспечивает производительность?
Этот ответ по другому вопросу был несколько полезен, но я не понимаю, почему этот ответ делает это:
def foo_constructor(loader, node):
instance = Foo.__new__(Foo)
yield instance
state = loader.construct_mapping(node, deep=True)
instance.__init__(**state)
вместо этого:
def foo_constructor(loader, node):
state = loader.construct_mapping(node, deep=True)
return Foo(**state)
Я тестировал, что последняя форма работает для примеров, опубликованных на этом другом ответе, но, возможно, мне не хватает какого-то края.
Я использую версию 3.10 PyYAML, но похоже, что код, о котором идет речь, в последней версии (3.12) PyYAML одинаков.