典型的な ConfigParser 生成ファイルは次のようになります。
[Section]
bar=foo
[Section 2]
bar2= baz
たとえば、次のようなリストにインデックスを付ける方法はありますか。
[Section 3]
barList={
item1,
item2
}
典型的な ConfigParser 生成ファイルは次のようになります。
[Section]
bar=foo
[Section 2]
bar2= baz
たとえば、次のようなリストにインデックスを付ける方法はありますか。
[Section 3]
barList={
item1,
item2
}
ConfigParser と JSON の組み合わせを使用しています。
[Foo]
fibs: [1,1,2,3,5,8,13]
それを読むだけです:
>>> json.loads(config.get("Foo","fibs"))
[1, 1, 2, 3, 5, 8, 13]
リストが長い場合は改行することもできます (@peter-smit に感謝):
[Bar]
files_to_check = [
"/path/to/file1",
"/path/to/file2",
"/path/to/another file with space in the name"
]
もちろん、JSON を使用することもできますが、構成ファイルははるかに読みやすく、[DEFAULT] セクションは非常に便利です。
リストを区切り文字列にパックし、構成から文字列を取得したら、リストをアンパックすることを妨げるものは何もありません。このようにすると、構成セクションは次のようになります。
[Section 3]
barList=item1,item2
きれいではありませんが、ほとんどの単純なリストで機能します。
私は最近、リストの構成ファイルに専用のセクションを追加してこれを実装しました。
[paths]
path1 = /some/path/
path2 = /another/path/
...
config.items( "paths" )
次のように、パス項目の反復可能なリストを取得するために使用します。
path_items = config.items( "paths" )
for key, path in path_items:
#do something with path
これが他の人々がこの質問をグーグルで検索するのに役立つことを願っています;)
多くの人が知らないことの 1 つは、複数行の構成値が許可されていることです。例えば:
;test.ini
[hello]
barlist =
item1
item2
の値は次のconfig.get('hello','barlist')
ようになります。
"\nitem1\nitem2"
これは splitlines メソッドで簡単に分割できます (空のアイテムをフィルタリングすることを忘れないでください)。
Pyramid のような大きなフレームワークに目を向けると、彼らは次の手法を使用しています。
def aslist_cronly(value):
if isinstance(value, string_types):
value = filter(None, [x.strip() for x in value.splitlines()])
return list(value)
def aslist(value, flatten=True):
""" Return a list of strings, separating the input based on newlines
and, if flatten=True (the default), also split on spaces within
each line."""
values = aslist_cronly(value)
if not flatten:
return values
result = []
for value in values:
subvalues = value.split()
result.extend(subvalues)
return result
私自身、これがあなたにとって一般的なことであれば、おそらく ConfigParser を拡張します。
class MyConfigParser(ConfigParser):
def getlist(self,section,option):
value = self.get(section,option)
return list(filter(None, (x.strip() for x in value.splitlines())))
def getlistint(self,section,option):
return [int(x) for x in self.getlist(section,option)]
この手法を使用する際には、注意すべき点がいくつかあることに注意してください。
文字通りリストを渡したい場合は、次を使用できます。
ast.literal_eval()
構成例:
[section]
option=["item1","item2","item3"]
コードは次のとおりです。
import ConfigParser
import ast
my_list = ast.literal_eval(config.get("section", "option"))
print(type(my_list))
print(my_list)
出力:
<type'list'>
["item1","item2","item3"]
私はこれを消費するためにここに着陸しました...
[global]
spys = richard.sorge@cccp.gov, mata.hari@deutschland.gov
答えは、カンマで分割してスペースを取り除くことです。
SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]
リスト結果を取得するには:
['richard.sorge@cccp.gov', 'mata.hari@deutschland.gov']
OPの質問に正確に答えないかもしれませんが、一部の人が探している簡単な答えかもしれません.
これは私がリストに使用するものです:
構成ファイルの内容:
[sect]
alist = a
b
c
コード:
l = config.get('sect', 'alist').split('\n')
文字列に対して機能します
数字の場合
設定内容:
nlist = 1
2
3
コード:
nl = config.get('sect', 'alist').split('\n')
l = [int(nl) for x in nl]
ありがとう。
構成パーサーによるシリアル化では、プリミティブ型のみがサポートされています。そのような要件には、JSON または YAML を使用します。
Grr の回答 (私のお気に入り) をさらに一歩進めるには、.ini ファイルでリスト項目を引用符で囲む代わりに、map 関数を使用できます。これにより、リスト項目のデータ型を Python で指定できます。
構成ファイル:
[section]
listKey1: 1001, 1002, 1003
listKey2: AAAA, BBBB, CCCC
コード:
cfgFile = 'config.ini'
parser = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
parser.read(cfgFile)
list1 = list(map(int, parser.getlist('section', 'listKey1')))
list2 = list(map(str, parser.getlist('section', 'listKey2')))
print(list1)
print(list2)
出力:
[1001, 1002, 1003]
['AAAA', 'BBBB', 'CCCC']
私は過去に同じ問題に直面しました。より複雑なリストが必要な場合は、ConfigParserから継承して独自のパーサーを作成することを検討してください。次に、getメソッドを次のように上書きします。
def get(self, section, option):
""" Get a parameter
if the returning value is a list, convert string value to a python list"""
value = SafeConfigParser.get(self, section, option)
if (value[0] == "[") and (value[-1] == "]"):
return eval(value)
else:
return value
このソリューションを使用すると、構成ファイルで辞書を定義することもできます。
ただし、注意してください。これはそれほど安全ではありません。これは、誰でも設定ファイルを介してコードを実行できることを意味します。プロジェクトでセキュリティが問題にならない場合は、Pythonクラスを構成ファイルとして直接使用することを検討します。以下は、ConfigParserファイルよりもはるかに強力で消費可能です。
class Section
bar = foo
class Section2
bar2 = baz
class Section3
barList=[ item1, item2 ]
import ConfigParser
import os
class Parser(object):
"""attributes may need additional manipulation"""
def __init__(self, section):
"""section to retun all options on, formatted as an object
transforms all comma-delimited options to lists
comma-delimited lists with colons are transformed to dicts
dicts will have values expressed as lists, no matter the length
"""
c = ConfigParser.RawConfigParser()
c.read(os.path.join(os.path.dirname(__file__), 'config.cfg'))
self.section_name = section
self.__dict__.update({k:v for k, v in c.items(section)})
#transform all ',' into lists, all ':' into dicts
for key, value in self.__dict__.items():
if value.find(':') > 0:
#dict
vals = value.split(',')
dicts = [{k:v} for k, v in [d.split(':') for d in vals]]
merged = {}
for d in dicts:
for k, v in d.items():
merged.setdefault(k, []).append(v)
self.__dict__[key] = merged
elif value.find(',') > 0:
#list
self.__dict__[key] = value.split(',')
これで、私のconfig.cfg
ファイルは次のようになります。
[server]
credentials=username:admin,password:$3<r3t
loggingdirs=/tmp/logs,~/logs,/var/lib/www/logs
timeoutwait=15
私の小さなプロジェクトに十分な粒度の細かいオブジェクトに解析できます。
>>> import config
>>> my_server = config.Parser('server')
>>> my_server.credentials
{'username': ['admin'], 'password', ['$3<r3t']}
>>> my_server.loggingdirs:
['/tmp/logs', '~/logs', '/var/lib/www/logs']
>>> my_server.timeoutwait
'15'
Parser
これは、単純な構成を非常に迅速に解析するためのものです。 から返されたオブジェクトを変換したり、他の場所で Parser クラスによって実行された解析ジョブを再実行したりせずに、int、bool、およびその他のタイプの出力をフェッチするすべての機能を失います。