web-dev-qa-db-ja.com

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が発生します。

注:defaults = just {'Apple': None, 'pear': None, 'banana': None }(セクションなし)でも試してみました

12
Nick Humrich

別のアプローチ:

ConfigParser.get は、渡すことができるvarsパラメータを提供します。これは、提供されている場合はプライマリルックアップとして使用されますが、オプションの値がすでに存在するかどうかは無視されます。セクション。

したがって、ダックタイピングを介して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がスローされます。

これを克服する方法は2つあります。

  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
_

しかし、これはワンライナーではないので、私が提供したDefaultOptionクラスのようなより多くのパスを開きます。少しでも冗長にすることができます。

7

取得したい複雑さに応じて、これを処理するいくつかの方法があります。

最も簡単な方法は、おそらくロジックをチェーンすることです。 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
10
user764357

あなたはすでにあなたの質問にあなたの答えを持っているように私には見えます:

_def get_with_default(section,name,default)
    try:
        return config.get(section,'Apple')
    except (NoSectionError, NoOptionError):
        return default
_

別の方法として、セクションごとにデフォルトでdictを設定し、ファイルから構成をロードする前にconfigparserでread_dict(defaults)を呼び出すこともできます。これにより、セクションが欠落していないことが保証されるため、例外がスローされません。

1
Wogan

必要に応じて、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
1
pcurry

ラッパー関数で例外を処理する方がおそらく効率的です。例外処理を回避する必要がある場合は、複合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
1
Robert Dean

繰り返さないのはどうですか?そうすれば、エラーをキャッチする必要があるときに、それほど面倒ではありません。

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はすでにこの方法で解決しました...

0
jakab922