Python configparser获取和设置没有例外

Nic*_*ich 12 python configparser

每次尝试获取或设置为使用configparserPython NoSectionError的部分时,如果该部分不存在,则抛出一个部分.反正有没有避免这个?另外,我还可以避免NoOptionError在获得选项时吗?

例如,使用字典,有setdefault选项:KeyError当键不存在时,字典会添加键,将键的值设置为默认值,然后返回默认值.

我目前正在执行以下操作来获取属性:

def read_config(section):
    config = configparser.ConfigParser()
    config.read(location)
    try:
        apple = config.get(section, 'apple')
    except NoSectionError, NoOptionError:
        apple = None
    try:
        pear = config.get(section, 'pear')
    except NoSectionError, NoOptionError:
        pear = None
    try:
        banana = config(section, 'banana')
    except NoSectionError, NoOptionError:
        banana = None
    return apple, pear, banana
Run Code Online (Sandbox Code Playgroud)

以下是设置它们:

def save_to_config(section, apple, pear, banana):
    config = configparser.ConfigParser()
    if not os.path.exists(folder_location):
        os.makedirs(folder_location)

    config.read(location)
    if section not in config.sections():
        config.add_section(section)

    config.set(section, 'apple', apple)
    config.set(section, 'pear', pear)
    config.set(section, 'banana', banana)
Run Code Online (Sandbox Code Playgroud)

设置不是太糟糕,因为它们都有相同的部分,但是很好......很糟糕.必须有一个更好的方法.

是否有一个衬垫,我可以减少这个:

try:
    apple = config.get(section, 'apple')
except NoSectionError, NoOptionError:
    apple = None
Run Code Online (Sandbox Code Playgroud)

对此:

apple = config.get_with_default(section, 'apple', None)
Run Code Online (Sandbox Code Playgroud)

- 编辑 -

我试图根据lego的建议进行以下更改:

def read_config(section):
    defaults = { section : {'apple': None,
                            'pear': None,
                            'banana': None }} 
    config = configparser.ConfigParser(defaults = defaults)
    config.read(location)

    apple = config.get(section, 'apple')
    pear = config.get(section, 'pear')
    banana = config(section, 'banana')

    return apple, pear, banana
Run Code Online (Sandbox Code Playgroud)

NoSectionError如果该部分不存在,这仍然会引发一个问题

注意:我也尝试过defaults = just {'apple': None, 'pear': None, 'banana': None } (没有部分)

小智 10

根据您想要获得的复杂程度,有几种方法可以解决这个问题.

最简单的方法可能就是将逻辑链接在一起.ConfigParser定义has_option以安全地检查某个部分是否存在选项.

apple = config.has_option(section,'apple') and config.get(section,'apple') or None
Run Code Online (Sandbox Code Playgroud)

或者,如果您提前知道哪些选项应具有值,则可以defaults在实例化解析器时设置字典.这样做的好处是可以保留和提高您不了解的部分的任何错误.

 myDefaults = {'apple':None,'banana':None,'pear':None}
 config = configparser.ConfigParser(defaults=myDefaults)
Run Code Online (Sandbox Code Playgroud)

如Wogan所述,您可以创建一个包装函数,但您可以轻松再次使用,has_option如下所示:

def get_with_default(config,section,name,default)
    if config.has_option(section,name):
        return config.get(section,name)
    else:
        return default
Run Code Online (Sandbox Code Playgroud)


Mah*_*der 7

另一种方法:

ConfigParser.get提供了一个vars可以传入的参数,如果提供了该参数,则该参数将用作主查找,但是,它会忽略该部分上是否存在该选项的值.

因此,我们可以vars通过ducktyping 使用,但我们会将行为更改.items()为以下内容:

  • 如果配置对象具有我们已经在寻找的选项,我们将采用它.
  • 否则,我们将从中返回默认值vars.

这是一个非常天真的实现:

class DefaultOption(dict):

    def __init__(self, config, section, **kv):
        self._config = config
        self._section = section
        dict.__init__(self, **kv)

    def items(self):
        _items = []
        for option in self:
            if not self._config.has_option(self._section, option):
                _items.append((option, self[option]))
            else:
                value_in_config = self._config.get(self._section, option)
                _items.append((option, value_in_config))
        return _items
Run Code Online (Sandbox Code Playgroud)

用法:

def read_config(section, location):
    config = configparser.ConfigParser()
    config.read(location)
    apple = config.get(section, 'apple',
                       vars=DefaultOption(config, section, apple=None))
    pear = config.get(section, 'pear',
                      vars=DefaultOption(config, section, pear=None))
    banana = config.get(section, 'banana',
                        vars=DefaultOption(config, section, banana=None))
    return apple, pear, banana

def save_to_config(section, location, apple, pear, banana):
    config = configparser.ConfigParser()

    config.read(location)
    if section not in config.sections():
        config.add_section(section)

    config.set(section, 'apple', apple)
    config.set(section, 'pear', pear)
    with open(location, 'wb') as cf:
        config.write(cf)
Run Code Online (Sandbox Code Playgroud)

话虽如此,这是一个间接的,但完全有效.

请注意,这仍然会提高NoSectionError.

如果您也尝试处理它,ConfigParser.ConfigParser会获取一个dict_type参数,因此您只需使用defaultdict实例化该类.

所以,configparser.ConfigParser()改为configparser.ConfigParser(dict_type=lambda: defaultdict(list))

但是,出于所有意图和目的,我可能会使用乐高的建议.

更新原始问题编辑

如果要将defaults关键字用于ConfigParser,可能有助于查看实现的定义方式.这是默认值初始化的ConfigParser.__init__()代码.您会看到默认值的使用方式与部分完全不同.要更深入地了解他们所扮演的角色get(),请查看代码ConfigParser.get().基本上,如果该部分不是DEFAULTSECT,则NoSectionError抛出a.

你有两种方法可以解决这个问题:

  1. 使用defaultdict我上面提出的想法
  2. read_config稍微修改你的功能
def read_config(section):
    defaults = {'apple': None,
                'pear': None,
                'banana': None }
    config = configparser.ConfigParser(defaults = defaults)
    config.read(location)
    if not config.has_section(section):
        config.add_section(section)

    apple = config.get(section,'apple')
    pear = config.get(section, 'pear')
    banana = config.get(section, 'banana')

    return apple, pear, banana
Run Code Online (Sandbox Code Playgroud)

但我说,因为这不是一个单行,它开辟了更多的路径,就像DefaultOption我提供的课程.我们可以使它更加冗长.