Creating a class with all the elements specified in a file using ConfigParser

后端 未结 3 1421
死守一世寂寞
死守一世寂寞 2020-12-09 07:02

I have created a .ini-like file with all the values which I need later in my program, see below:

[debugging]
checkForAbort = 10
...

[official]
checkForAbort         


        
相关标签:
3条回答
  • 2020-12-09 07:53

    The Answer by pillmuncher is very helpful and can be easily adapted to use within an existing class. Furthermore, it is also possible to automatically convert the data types using the localconfig module (link). To get these additional functionalities you can use something like:

    from localconfig import LocalConfig
    
    configfile = 'config.ini'
    config = LocalConfig(configfile)
    sections = list(config)
    
    for section in sections:
        items = list(config.items(section))
        CLASS.__dict__.update(items)
    
    0 讨论(0)
  • 2020-12-09 07:54

    What J.F. Sebastian said.

    Also, you could do it like Alex Martelli does in his Bunch class:

    file MyConfig.py:

    from ConfigParser import SafeConfigParser
    
    
    section_names = 'official', 'debugging'
    
    
    class MyConfiguration(object):
    
        def __init__(self, *file_names):
            parser = SafeConfigParser()
            parser.optionxform = str  # make option names case sensitive
            found = parser.read(file_names)
            if not found:
                raise ValueError('No config file found!')
            for name in section_names:
                self.__dict__.update(parser.items(name))  # <-- here the magic happens
    
    
    config = MyConfiguration('my.cfg', 'other.cfg')
    

    file foo.py:

    from MyConfig import config
    # ...
    

    file MyProgram.py:

    from MyConfig import config
    
    print config.checkForAbort
    
    import foo
    
    assert config is foo.config
    

    The Python Language Reference states that "Import statements are executed in two steps: (1) find a module, and initialize it if necessary; (2) define a name or names in the local namespace (of the scope where the import statement occurs)."

    What that means is that, when a module gets imported, one or more local names are bound to a module object, and only the first time it is imported during the runtime of a Python program it gets initialized (i.e. read from file and run).

    In the code above the name config is just a local name that refers to an attribute of a module object. The module object has been initialized by the Python interpreter when it was referenced (via from MyConfig import config) in MyProgram. When MyProgram imports foo it is already initialized and gets bound to a local name in module foo and in MyProgram we can refer to it as foo.config. But both names refer to the very same object.

    0 讨论(0)
  • 2020-12-09 07:54

    self.name = value doesn't work as you expect. You might mean setattr(self, name, value) It creates instance attributes dynamicallly.

    To make it a singleton you could make the instance to be a global variable in config/settings module. Initialize it once on a program startup e.g., like the logging module does it for the root logger: logging.config.fileConfig('logging.conf').

    It is a common desire to use an attribute access for what is essentially a dict e.g., argparse.Namespace that carries command-line options.

    You could access the config later by importing it: from mypackage.config import config, e.g., mypackage/config.py:

    class Config(object):
        ...
    
    config = Config() # empty or default config without any configuration
    

    In mypackage/__main__.py:

    from .config import config
    ...
    # initialization code
    config.update_from_file('mypackage.conf') # it might call `setattr()` inside
    

    Note: setattr() works correctly even you set properties. __dict__.update() breaks in this case:

    class XValidatorMixin(object):
        @property
        def x(self):
            return self._x
    
        @x.setter
        def x(self, value):
            if value < 0:
                raise ValueError
            self._x = value
    
    
    class CUpdate(XValidatorMixin):
        def __init__(self, **options):
            self.__dict__.update(options)
    
    
    class CSetAttr(XValidatorMixin):
        def __init__(self, **options):
            for name, value in options.items():
                setattr(self, name, value)
    
    for C in [CUpdate, CSetAttr]:
        o = C(a=1, b=2) # non-property attributes work as expected
        assert o.a == 1 and o.b == 2
    
    o = CSetAttr(x=1)
    assert o.x == 1 # setattr also sets property
    
    o = CUpdate(x=1)
    try:
        o.x # .update() doesn't set property
    except AttributeError:
        pass
    else:
        assert 0
    
    
    try:
        o = CSetAttr(x=-1)  # invokes property setter
    except ValueError: # that correctly reject negative values
        pass
    else:
        assert 0
    
    0 讨论(0)
提交回复
热议问题