How to update configuration on each read?

隐身守侯 提交于 2021-01-27 17:48:07

问题


So I have this class:

import yaml

class Config():
        def __init__(self, filename):
                self.config_filename=filename

        def __read_config_file(self):
                with open(self.config_filename) as f:
                        self.cfg = yaml.safe_load(f)

        def get(self):
                self.__read_config_file()
                return self.cfg

And it works fine. The thought behind it is to force a reread of the config file every time I use something in the configuration. Here is an example of usage:

cfg = Config('myconfig.yaml')

for name in cfg.get()['persons']:
    print (cfg.get()['persons'][name]['phone']) 
    print (cfg.get()['persons'][name]['address']) 

This works, but I think it looks extremely ugly. I could do something like this:

c = cfg.get()['persons']
for name in c:
    print (c['persons'][name]['phone']) 
    print (c['persons'][name]['address']) 

Which looks just a tiny bit better, but I also lose the benefit of reloading on access, but what I want to do is something this (which obviously does not work):

for name in c:
    print (name['phone']) 
    print (name['address'])

It seems like it's something I don't understand about iterating over dictionaries, but my main concern here is that I want to reload the configuration file each time any value from that file is used, and I want it in a nice readable way. So how can I redesign this?

Example of configuration file. It's possible to change the format here if necessary.

persons:
    john:
        address: "street A"
        phone: "123"
    george:
        address: "street B"
        phone: "456"

回答1:


Since it is a dict, normal iteration doesn't work. we can iterate through the dictionary by the following method,

for name, person in c.items():
   print(name)
   print(person['phone']) 
   print(person['address'])

Hope this helps




回答2:


I have made your 'persons' data :

persons={}
persons["name"]={"john":{'phone':'123', 'address':'street A'}, 
                 "george":{'phone':'456', 'address':'street B'}}

Here is something interesting, you can get all the names that are written in "persons":

L_names = list(persons['name'].keys())
print(L_names)  # returns ['john', 'george']

So if you get the data of each character :

L_names_data = []
for i in list(persons['name'].keys()):
    L_names_data.append(persons['name'][i])

You can easily write what you wanted : (a nice and simple for loop)

for name_data in L_names_data:
    print(name_data['address'])
    print(name_data['phone'])

#returns :
#street A
#123
#street B
#456

The inconvenient is that you loose the 'name' info ('john' and 'george' strings don't appear in 'L_names_data' which is a list of dictionnaries).




回答3:


The user rasjani made some comments that helped me solve it. What I do is basically this:

import collections

class Config(collections.UserDict):
        def __getitem__(self, key):
                self.reload()
                return super().__getitem__(key)

        def reload(self):
                with open(self.filename) as f:
                        c=yaml.safe_load(f)
                super().__init__(c)

The actual class is more complicated with more error checking and features, but the above is what does the magic I asked about.

The method __getitem__ is called everytime you use the dictionary. So what I do is simply calling reload before calling __getitem__ from the superclass.

One should be aware of one exception here.

a = Config('myconf.yml')
b = a['field'] # Will reload the configuration file
c = a          # But this will not
d = c['field'] # However, this will

I thought about solving that by also modifying __getattribute__ in the same way, but I ended up with all sorts of problems with endless recursion, and in practice I am not sure if it is a problem worth solving, or even a problem at all.



来源:https://stackoverflow.com/questions/61652216/how-to-update-configuration-on-each-read

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!