How to download a pyYAML file and access it using attributes instead of using dictionary notation?

I have a YAML configuration that looks like this:

config: - id: foo - name: bar content: - run: xxx - remove: yyy 

I use the Python YAML module to load it, but I want to access it in more efficient ways, for example:

 stream = open(filename) config = load(stream, Loader=Loader) print(config['content']) 

I want me to be able to: print(config.content) .

+6
source share
2 answers

You can use object notation with dictionaries using the following class, as described in this :

 class DictAsMember(dict): def __getattr__(self, name): value = self[name] if isinstance(value, dict): value = DictAsMember(value) return value 

This class in action:

 >>> my_dict = DictAsMember(one=1, two=2) >>> my_dict {'two': 2, 'one': 1} >>> my_dict.two 2 

Change This works recursively with sub-dictionaries, for example:

 >>> my_dict = DictAsMember(one=1, two=2, subdict=dict(three=3, four=4)) >>> my_dict.one 1 >>> my_dict.subdict {'four': 4, 'three': 3} >>> my_dict.subdict.four 4 
+5
source

The easiest way to do this is probably to rewrite the YAML constructor for tag:yaml.org,2002:map so that it returns its own dictionary class instead of a regular dictionary.

 import yaml class AttrDict(object): def __init__(self, attr): self._attr = attr def __getattr__(self, attr): try: return self._attr[attr] except KeyError: raise AttributeError def construct_map(self, node): # WARNING: This is copy/pasted without understanding! d = {} yield AttrDict(d) d.update(self.construct_mapping(node)) # WARNING: We are monkey patching PyYAML, and this will affect other clients! yaml.add_constructor('tag:yaml.org,2002:map', construct_map) YAML = """ config: - id: foo - name: bar content: - run: xxx - remove: yyy """ obj = yaml.load(YAML) print(obj.config[0].id) # prints foo 

Note that this will break everything else in a process that uses YAML if it expects everything to work in the usual Python way. You can use a custom loader, but I personally find the PyYAML documentation a bit labyrinthine and it seems that the side effects are global and contagious, and not as an exception.

You have been warned.

Alternatively , if your schema is relatively static, you can write your own classes and deserialize them (e.g. class Config with id and name properties). However, it probably would not be worth the cost of additional code.

+4
source

Source: https://habr.com/ru/post/918161/


All Articles