Python configparser获取和设置没有例外

时间:2014-07-18 19:43:02

标签: python configparser

每当您尝试在Python中使用configparser获取或设置某个部分时,如果该部分不存在,则会抛出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

以下设置它们:

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)

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

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

try:
    apple = config.get(section, 'apple')
except NoSectionError, NoOptionError:
    apple = None

到此:

apple = config.get_with_default(section, 'apple', None)

- 编辑 -

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

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

但如果该部分不存在,这仍会引发NoSectionError

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

6 个答案:

答案 0 :(得分:9)

有几种方法可以解决这个问题,具体取决于你想要的复杂程度。

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

apple = config.has_option(section,'apple') and config.get(section,'apple') or None

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

 myDefaults = {'apple':None,'banana':None,'pear':None}
 config = configparser.ConfigParser(defaults=myDefaults)

如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

答案 1 :(得分:7)

另一种方法:

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

因此,我们可以通过ducktyping使用vars,但我们会将.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

用法:

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)

话虽如此,这有点间接,但完全有效。

请注意,这仍然会引发NoSectionError

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

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

尽管如此,我可能会使用乐高的建议。

原始问题编辑的更新

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

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

  1. 使用我上面提出的defaultdict想法
  2. 稍微修改您的read_config功能
  3. 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
    

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

答案 2 :(得分:1)

在我看来你已经在你的问题中得到了答案:

def get_with_default(section,name,default)
    try:
        return config.get(section,'apple')
    except (NoSectionError, NoOptionError):
        return default

另一种方法是为每个部分设置一个dict默认值,并在从文件加载配置之前在configparser上调用read_dict(defaults)。这应该确保没有任何部分丢失&因此不会抛出异常。

答案 3 :(得分:1)

你可以编写一个包装函数来获得dict.setdefault行为,如果这是你想要的:

def config_setdefault_get(config, section, key, default)
    result = default
    try:
        result = config.get(section, key)
    except NoSectionError:
        config.add_section(section)
        config.set(section, key, default)
    except NoOptionError:
        config.set(section, key, default)
    finally:
        return result

答案 4 :(得分:1)

在包装函数中处理异常可能更有效。如果必须避免异常处理,则化合物if可以解决问题。

def get_with_default(section,name,default)
    return config.get(section,name) if config.has_section(section) and config.has_option(section, option) else default

答案 5 :(得分:0)

不重复自己怎么样?当你必须捕捉错误时,这不是一件麻烦事。

def read_config(section, default=None, *vars):
    config = configparser.ConfigParser()
    config.read(location)
    ret = []
    for var in vars:
        try:
            ret.append(config.get(section, var))
        except NoSectionError, NoOptionError:
            ret.append(default)
    return ret

噢,是的,Wogan已经用这种方式解决了......