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 }
(セクションなし)でも試してみました
別のアプローチ:
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つあります。
defaultdict
のアイデアを使用してください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
クラスのようなより多くのパスを開きます。少しでも冗長にすることができます。
取得したい複雑さに応じて、これを処理するいくつかの方法があります。
最も簡単な方法は、おそらくロジックをチェーンすることです。 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
あなたはすでにあなたの質問にあなたの答えを持っているように私には見えます:
_def get_with_default(section,name,default)
try:
return config.get(section,'Apple')
except (NoSectionError, NoOptionError):
return default
_
別の方法として、セクションごとにデフォルトでdict
を設定し、ファイルから構成をロードする前にconfigparserでread_dict(defaults)
を呼び出すこともできます。これにより、セクションが欠落していないことが保証されるため、例外がスローされません。
必要に応じて、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
ラッパー関数で例外を処理する方がおそらく効率的です。例外処理を回避する必要がある場合は、複合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
繰り返さないのはどうですか?そうすれば、エラーをキャッチする必要があるときに、それほど面倒ではありません。
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はすでにこの方法で解決しました...