Я читал исходный код PyYAML, чтобы попытаться понять, как определить правильную конструкторскую функцию, которую я могу добавить с помощью add_constructor
. У меня довольно хорошее представление о том, как работает этот код, но я до сих пор не понимаю, почему конструкторы YAML по умолчанию в SafeConstructor
являются генераторами. Так, например, метод construct_yaml_map
из SafeConstructor
:Почему PyYAML использует генераторы для создания объектов?
def construct_yaml_map(self, node):
data = {}
yield data
value = self.construct_mapping(node)
data.update(value)
Я понимаю, как генератор используется в BaseConstructor.construct_object
следующим образом, чтобы гасит объект, и только заполнить его с данными из узла, если 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, или это дает преимущество в производительности?
This answer on another question было несколько полезно, но я не понимаю, почему этот ответ делает это:
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.
Добро пожаловать в Stackoverflow. – Randy