¿Cómo usar la clase de diccionario personalizada al cargar yaml?

Actualmente estoy cargando un archivo YAML como este

import yaml yaml.load('''level0: stuff: string0 level1: stuff: string1 level2: ...''') 

El código anterior crea diccionarios nesteds . En lugar de crear diccionarios nesteds, quiero crear instancias anidadas de objetos FancyDict .

 class FancyDict(collections.MutableMapping): def __init__(self, *args, **kwargs): for name in kwargs: setattr(self, name, kwargs[name]) 

La sección sobre Constructores, Representante, Resolvers no parece abordar este caso en el que deseo anular globalmente la construcción de clase para todos los diccionarios en lugar de los etiquetados especiales.

Solo necesito que se cree / finalice un enlace que se llamaría objeto (¿nodo?).
¿Hay una manera fácil de hacer esto o debo atravesar los diccionarios nesteds que yaml.load devuelve un yaml.load y solucionarlos yo mismo?

Ese gancho no está allí, el tipo que se construye está codificado de forma rígida en construct.BaseConstructor.construct_mapping() .

La manera de resolver esto es crear su propio constructor y basarse en ese su propio cargador, y entregarlo como opción para load() :

 import sys import collections import ruamel.yaml as yaml yaml_str = """\ level0: stuff: string0 level1: stuff: string1 level2: ... """ from ruamel.yaml.reader import Reader from ruamel.yaml.scanner import Scanner from ruamel.yaml.parser import Parser from ruamel.yaml.composer import Composer from ruamel.yaml.constructor import SafeConstructor from ruamel.yaml.resolver import Resolver from ruamel.yaml.nodes import MappingNode class FancyDict(collections.MutableMapping): def __init__(self, *args, **kwargs): for name in kwargs: setattr(self, name, kwargs[name]) # provide the missing __getitem__, __setitem__, __delitem__, __iter__, and __len__. class MyConstructor(SafeConstructor): def construct_mapping(self, node, deep=False): res = SafeConstructor.construct_mapping(self, node, deep) assert isinstance(res, dict) return FancyDict(**res) class MyLoader(Reader, Scanner, Parser, Composer, MyConstructor, Resolver): def __init__(self, stream, version=None): Reader.__init__(self, stream) Scanner.__init__(self) Parser.__init__(self) Composer.__init__(self) MyConstructor.__init__(self) Resolver.__init__(self) data = yaml.load(yaml_str, Loader=MyLoader) 

Cuando ejecute esto, obtendrá un error de que FancyDict es una clase abstracta que no puede ser instanciada:

TypeError: No se puede crear una instancia de la clase abstracta FancyDict con métodos abstractos __delitem__ , __getitem__ , __iter__ , __len__ , __setitem__

Supongo que tu verdadero FancyDict tiene esos implementados.


ruamel.yaml es una biblioteca YAML que admite YAML 1.2 (recomiendo usar eso, pero luego soy el autor del paquete). PyYAML solo admite (la mayoría de) YAML 1.1. Más problemáticamente, tiene diferentes archivos constructor.py para Python2 y Python3, es posible que no puedas colocar el código anterior en PyYAML debido a eso.