LoginSignup
211
229

More than 3 years have passed since last update.

pythonプログラムにおける設定ファイル管理モジュール~configparserの使い方と注意点~

Last updated at Posted at 2019-08-06

はじめに

アプリケーションを作る際は、アプリ自身の設定ファイルは必要になることが多々あります。
pythonでは設定ファイルを管理する内部モジュールとしてconfigparserがあります。
便利なモジュールですが、実際に使うと色々な注意点が必要なのでその情報をまとめてみました。

単純な使い方

まずは以下のconfig.ini(設定ファイル)を読み込みデータを表示させる簡単な例を作成します。
簡単にするためconfig.iniは実行するpythonファイルと同ディレクトリに配置します。
今回は[DEFAULT]セクションの「User」の値を取得します。

config.ini
[DEFAULT]
User = Taro
Friend = Brother
Age = 20
No = 1
Default_nengo = 昭和
is_Hero = yes

[ULTRAMAN]
User = Hayata
Skil = Spacium beam
Age = 200000
No = 2

[Masked Rider]
User = Takeshi
Frined = Hayato
Machine = Cyclone
Age = 23
configparser_sample1.py
# coding: utf-8
import configparser


# --------------------------------------------------
# configparserの宣言とiniファイルの読み込み
# --------------------------------------------------
config_ini = configparser.ConfigParser()
config_ini.read('config.ini', encoding='utf-8')


# --------------------------------------------------
# config,iniから値取得
# --------------------------------------------------
# config.iniの値取得その1
var1 = config_ini['DEFAULT']['User']

# config.iniの値取得その2
var2 = config_ini.get('DEFAULT', 'User')

# config.iniの値取得その3
read_default = config_ini['DEFAULT']
var3 = read_default['User']

# config.iniの値取得その4
read_default = config_ini['DEFAULT']
var4 = read_default.get('User')


# --------------------------------------------------
# 結果表示
# --------------------------------------------------
print('var1 :', var1)
print('var2 :', var2)
print('var3 :', var3)
print('var4 :', var4)
実行結果
var1 : Taro
var2 : Taro
var3 : Taro
var4 : Taro

上記の通り、4つの手法で値を取得可能です。
個人的によく使うのは取得方法その4です。
上記は必要最低限の方法でconfig.iniの値を取得しています。
しかし実際に使用する際は注意点があります。
そのため以下に使い方と注意点について説明します。
尚、本説明ではconfig.iniには常に上記のものを利用します。

設定ファイル(config.ini)の読み込みと注意点

設定ファイル(config.ini)を読み込むread()関数は、読み込む対象のファイルが存在するかチェックしません。
存在しない設定ファイルを指定した場合、Noneとなります。

configparser_sample2.py
# coding: utf-8
import configparser


# --------------------------------------------------
# 存在しないiniファイルの読み込み
# --------------------------------------------------
config_ini = configparser.ConfigParser()
config_ini.read('hoge.ini', encoding='utf-8')

# hoge.iniの値取得(存在しないためNone)
read_default = config_ini['DEFAULT']
var = read_default.get('User')

# 結果表示(Noneが表示)
print('var :', var)
実行結果
var : None

よって次のように別途、config.iniが存在するかチェックする必要があります。
(あるいはconfig.iniから取得した値がNoneの場合の対応を記述します)

configparser_sample3.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# --------------------------------------------------
# iniファイルの読み込み
# --------------------------------------------------
config_ini = configparser.ConfigParser()
config_ini_path = 'hoge.ini'

# 指定したiniファイルが存在しない場合、エラー発生
if not os.path.exists(config_ini_path):
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)

config_ini.read(config_ini_path, encoding='utf-8')

# iniの値取得
read_default = config_ini['DEFAULT']
var = read_default.get('User')

# 結果表示
print('var :', var)
実行結果
FileNotFoundError: [Errno 2] No such file or directory: 'hoge.ini'

想定通り、hoge.iniは存在しないため、「raise FileNotFoundError」が実行されます。

余談ですが、read()関数を使ってopen()したファイルはread()関数内でclose()されます。
そのため別途colose処理を実施する必要はありません。

read_fileの利用

ファイルのopen()処理をconfigparserに任せたくない場合はread_file()関数を使います。
こちらはread()関数と異なり、open()したファイルを引数に渡します。

configparser_sample4.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# --------------------------------------------------
# read_file()関数によるiniファイルの読み込み
# --------------------------------------------------
config_ini = configparser.ConfigParser()
config_ini_path = 'config.ini'

# iniファイルが存在するかチェック
if os.path.exists(config_ini_path):
    # iniファイルが存在する場合、ファイルを読み込む
    with open(config_ini_path, encoding='utf-8') as fp:
        config_ini.read_file(fp)

        # iniの値取得
        read_default = config_ini['DEFAULT']
        var = read_default.get('User')

        # 結果表示
        print('var :', var)
else:
    # iniファイルが存在しない場合、エラー発生
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)
実行結果
var : Taro

上記の通り、ファイルのopen()、close()のタイミングは自分で決められます。
(今回はwith句を使用しているためclose()は記述していませんが)
ファイル関連は別クラスで管理したい、または設定ファイル(config.ini)に追記する場合など、
より応用的に使うときに便利な関数です。

設定ファイル(config.ini)の値取得方法と注意点

設定ファイル(config.ini)は角括弧([])によって区別されるセクション毎に値が管理されています。
今までは[DEFAULT]セクションの「User」キーの値を取得していたため、「Taro」が得られました。
これを[ULTRAMAN]セクションの「Skil」キーから取得すれば「Spacium beam」が得られます。

余談ですが、存在しないキーから値を取得した場合、エラーではなくNoneとなります。

configparser_sample5.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# iniファイルの読み込み
config_ini = configparser.ConfigParser()
config_ini_path = 'config.ini'

# 指定したiniファイルが存在しない場合、エラー発生
if not os.path.exists(config_ini_path):
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)

config_ini.read(config_ini_path, encoding='utf-8')

# [ULTRAMAN]の「Skil」キーの値を取得
read_ultraman = config_ini['ULTRAMAN']
var = read_ultraman.get('Skil')

# 存在しないキーの値を取得
none_var = read_ultraman.get('Hoge')

# 結果表示
print('var :', var)
print('none_var :', none_var)
結果表示
var : Spacium beam
none_var : None

[DEFAULT]の取り扱い

[DEFAULT]セクションは特別なセクションです。
他セクションで未設定の値がある場合、[DEFAULT]セクションの設定に準じます。
例えば[ULTRAMAN]セクションには「Friend」キーが未設定のため、[DEFAULT]セクションの「Friend」キーの値である「Brother」が反映されます。
同様に[Masked Rider]セクションは「No」キーが未設定のため、[DEFAULT]セクションの「No」キーの値である「1」が反映されます。

configparser_sample6.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# iniファイルの読み込み
config_ini = configparser.ConfigParser()
config_ini_path = 'config.ini'

# 指定したiniファイルが存在しない場合、エラー発生
if not os.path.exists(config_ini_path):
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)

config_ini.read(config_ini_path, encoding='utf-8')

# [ULTRAMAN]セクションの値取得
# 「Friend」キーは[ULTRAMAN]で未設定のため[DEFAULT]の「Brother」となる
read_ultraman = config_ini['ULTRAMAN']

# [Masked Rider]セクションの値取得
# 「No」キーは[Masked Rider]で未設定のため[DEFAULT]の「No」となる
read_masked_rider = config_ini['Masked Rider']

# 結果表示の体裁
result_str = """[{section_name}]
User   : {user}
Friend : {friend}
No     : {no}"""

# 結果表示
for read_conf in [read_ultraman, read_masked_rider]:
    # [ULTRAMAN]と[Masked Rider]セクションを順次表示
    print(result_str.format(
        section_name=read_conf.name,
        user=read_conf.get('User'),
        friend=read_conf.get('Friend'),
        no=read_conf.get('no')
    ))

    print()
結果表示
[ULTRAMAN]
User   : Hayata
Friend : Brother
No     : 2

[Masked Rider]
User   : Takeshi
Friend : Brother
No     : 1

データ型

get()関数で取得した設定ファイル(config.ini)のデータ型は全て文字列型となります。
一方でgetint()関数等で、特定のデータ型としても取得は可能です。
ですが取得対象データがint型に変換できない場合、getinit()はエラーとなります。
とりあえずget()関数で取得し、データ型の変換と例外処理は別途実施する、という方法も考えられます。
用途によって使い分けるとよいでしょう。

configparser_sample7.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# iniファイルの読み込み
config_ini = configparser.ConfigParser()
config_ini_path = 'config.ini'

# 指定したiniファイルが存在しない場合、エラー発生
if not os.path.exists(config_ini_path):
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)

config_ini.read(config_ini_path, encoding='utf-8')


# --------------------------------------------------
# get()で取得した値は全てstr型となる
# --------------------------------------------------
# [ULTRAMAN]セクションの「No」キー(数字)の値取得
read_ultraman = config_ini['ULTRAMAN']
ultraman_no = read_ultraman.get('No')

# 「No」キーの値のデータ型を表示
print('Get "No" Data Type : ', type(ultraman_no))
print('------------------------------')


# --------------------------------------------------
# getXXX()で取得した値はそれぞれ適応した値となる
# --------------------------------------------------
# getint()で[ULTRAMAN]セクションの「No」キー(数字)の値取得
ultraman_no_getint = read_ultraman.getint('No')

# getboolean()で[ULTRAMAN]セクションの「is_Hero」キー(数字)の値取得
ultraman_is_hero_getboolean = read_ultraman.getboolean('is_Hero')

# getXXX()で取得したデータ型を表示
print('Get "No" Data Type : ', type(ultraman_no_getint))
print('Get "is_Hero" Data Type : ', type(ultraman_is_hero_getboolean))
結果表示
Get "No" Data Type :  <class 'str'>
------------------------------
Get "No" Data Type :  <class 'int'>
Get "is_Hero" Data Type :  <class 'bool'>

まとめて取得

今まではデータを1つ1つ取得していましたが、まとめて取得する関数も用意されています。

configparser_sample8.py
# coding: utf-8
import configparser

# ファイルの存在チェック用モジュール
import os
import errno


# iniファイルの読み込み
config_ini = configparser.ConfigParser()
config_ini_path = 'config.ini'

# 指定したiniファイルが存在しない場合、エラー発生
if not os.path.exists(config_ini_path):
    raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), config_ini_path)

config_ini.read(config_ini_path, encoding='utf-8')


# --------------------------------------------------
# セクションの一覧取得
# ※DEFAULTセクションは表示されない点に注意
# --------------------------------------------------
sections_list = config_ini.sections()
print(sections_list)
print('------------------------------')


# --------------------------------------------------
# ULTRAMANの要素一覧
# --------------------------------------------------
ultraman_items = config_ini.items('ULTRAMAN')
print(ultraman_items)
# 辞書型に変換可能
print(dict(ultraman_items))
実行結果
['ULTRAMAN', 'Masked Rider']
------------------------------
[('user', 'Hayata'), ('friend', 'Brother'), ('age', '200000'), ('no', '2'), ('default_nengo', '昭和'), ('is_hero', 'yes'), ('skil', 'Spacium beam')]
{'user': 'Hayata', 'friend': 'Brother', 'age': '200000', 'no': '2', 'default_nengo': '昭和', 'is_hero': 'yes', 'skil': 'Spacium beam'}

上記の通り、セクション一覧、特定セクションのキーと値一覧が取得できます。
ただしitems()で取得するキーと値のペアには、[DEFAULT]セクションの値が含まれている点に注意してください。

参考リンク

211
229
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
211
229