典型的な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
}
回答:
リストを区切られた文字列にパックし、構成から文字列を取得したら、それをアンパックすることを妨げるものは何もありません。このようにすると、configセクションは次のようになります。
[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]セクションは非常に便利です。
key5 : [r"abc $x_i$", r"def $y_j$"]
ますか?彼らはエラーを上げるjson.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
このパーティーには遅くなりましたが、最近、リストの構成ファイルの専用セクションを使用してこれを実装しました。
[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
これがこの質問をグーグルする他の人々を助けることを願っています;)
; comment
リスト全体を書き直さなくてもリストから特定の項目を取り出すことができるので、このソリューションが気に入っています。
key
は、ConfigParserがそのようなすべてのキーを小文字に変換するため、も使用することに注意してください
config = ConfigParser.SafeConfigParser()
config.optionxform = str
その後、ケースはそのままになります
多くの人が知らないことの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)]
この手法を使用する場合は、注意すべき点がいくつかあります。
.splitlines()
代わりになぜ使用するの.split()
ですか?それぞれのデフォルトの動作を使用すると、splitは明らかに優れています(空白行をフィルターで除外します)。私が何かを見逃していない限り...
文字通りリストを渡したい場合は、以下を使用できます。
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"]
ast.literal_eval()
(おそらくより人気のある)を使用する場合と比較して使用する利点は何json.loads()
ですか?後者はより多くのセキュリティを提供すると思いますか?
のためのクワーグについての言及なしconverters
ConfigParser()
これらの回答のいずれはなく、むしろがっかりしたものでした。
ドキュメントによると、パーサーとセクションプロキシの両方にメソッドをConfigParser
追加する辞書を渡すことができget
ます。リストの場合:
example.ini
[Germ]
germs: a,list,of,names, and,1,2, 3,numbers
パーサーの例:
cp = ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]})
cp.read('example.ini')
cp.getlist('Germ', 'germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
cp['Germ'].getlist('germs')
['a', 'list', 'of', 'names', 'and', '1', '2', '3', 'numbers']
これは、私の個人的なお気に入りです。サブクラス化は必要なく、JSONやで解釈できるリストを完全に書き込むためにエンドユーザーに依存する必要はありませんast.literal_eval
。
私はこれを消費しようとしてここに上陸しました...
[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の質問に正確に答えないかもしれませんが、一部の人々が探している単純な答えかもしれません。
sorger@espionage.su
!私のメールがバウンスし続けたのも当然です!> _ <
だから私が好む別の方法は、単に値を分割することです、例えば:
#/path/to/config.cfg
[Numbers]
first_row = 1,2,4,8,12,24,36,48
次のように、このように文字列または整数のリストにロードできます。
import configparser
config = configparser.ConfigParser()
config.read('/path/to/config.cfg')
# Load into a list of strings
first_row_strings = config.get('Numbers', 'first_row').split(',')
# Load into a list of integers
first_row_integers = [int(x) for x in config.get('Numbers', 'first_row').split(',')]
このメソッドにより、JSONとしてロードするために値を角括弧で囲む必要がなくなります。
構成パーサーによる直列化では、プリミティブ型のみがサポートされています。この種の要件には、JSONまたはYAMLを使用します。
過去にも同じ問題に直面しました。より複雑なリストが必要な場合は、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 ]
barList=item1,item2
からを呼び出さないのはなぜですかif value.find(',') > 0: return value.split(',')
、またはさらに良いことに、アプリケーションにすべての設定オプションをリストとして解析させ、.split(',')
すべてを盲目的に解析させますか?
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'
これは、単純な構成の非常に迅速な解析のためのものです。int、bool、およびその他のタイプの出力をフェッチするすべての機能を失いParser
ます。
値のないキーを含むセクションでプロジェクトで同様のタスクを完了しました:
import configparser
# allow_no_value param says that no value keys are ok
config = configparser.ConfigParser(allow_no_value=True)
# overwrite optionxform method for overriding default behaviour (I didn't want lowercased keys)
config.optionxform = lambda optionstr: optionstr
config.read('./app.config')
features = list(config['FEATURES'].keys())
print(features)
出力:
['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']
app.config:
[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn
json.loads
& ast.literal_eval
は機能しているようですが、config内の単純なリストは各文字をバイトとして扱っているため、角括弧も返します。
構成がある場合の意味 fieldvalue = [1,2,3,4,5]
の代わりにconfig.read(*.cfg)
config['fieldValue'][0]
戻る[
1
Peter Smit(https://stackoverflow.com/a/11866695/7424596)が述べたように、ConfigParserを拡張することもできます。さらに、Interpolatorを使用して、リストとの間で自動的に変換できます。
下部の参照用に、次のような構成を自動的に変換するコードを見つけることができます。
[DEFAULT]
keys = [
Overall cost structure, Capacity, RAW MATERIALS,
BY-PRODUCT CREDITS, UTILITIES, PLANT GATE COST,
PROCESS DESCRIPTION, AT 50% CAPACITY, PRODUCTION COSTS,
INVESTMENT, US$ MILLION, PRODUCTION COSTS, US ¢/LB,
VARIABLE COSTS, PRODUCTION COSTS, MAINTENANCE MATERIALS
]
したがって、キーを要求すると、次のようになります。
<class 'list'>: ['Overall cost structure', 'Capacity', 'RAW MATERIALS', 'BY-PRODUCT CREDITS', 'UTILITIES', 'PLANT GATE COST', 'PROCESS DESCRIPTION', 'AT 50% CAPACITY', 'PRODUCTION COSTS', 'INVESTMENT', 'US$ MILLION', 'PRODUCTION COSTS', 'US ¢/LB', 'VARIABLE COSTS', 'PRODUCTION COSTS', 'MAINTENANCE MATERIALS']
コード:
class AdvancedInterpolator(Interpolation):
def before_get(self, parser, section, option, value, defaults):
is_list = re.search(parser.LIST_MATCHER, value)
if is_list:
return parser.getlist(section, option, raw=True)
return value
class AdvancedConfigParser(ConfigParser):
_DEFAULT_INTERPOLATION = AdvancedInterpolator()
LIST_SPLITTER = '\s*,\s*'
LIST_MATCHER = '^\[([\s\S]*)\]$'
def _to_list(self, str):
is_list = re.search(self.LIST_MATCHER, str)
if is_list:
return re.split(self.LIST_SPLITTER, is_list.group(1))
else:
return re.split(self.LIST_SPLITTER, str)
def getlist(self, section, option, conv=lambda x:x.strip(), *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self._get_conv(
section, option,
lambda value: [conv(x) for x in self._to_list(value)],
raw=raw,
vars=vars,
fallback=fallback,
**kwargs
)
def getlistint(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, int, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getlistfloat(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, float, raw=raw, vars=vars,
fallback=fallback, **kwargs)
def getlistboolean(self, section, option, *, raw=False, vars=None,
fallback=_UNSET, **kwargs):
return self.getlist(section, option, self._convert_to_boolean,
raw=raw, vars=vars, fallback=fallback, **kwargs)
Psはインデントの重要性を覚えています。ConfigParser doc文字列を読み取ると、次のようになります。
値は、値の最初の行よりもインデントされている限り、複数行にまたがることができます。パーサーのモードによっては、空白行が複数行の値の一部として扱われるか、無視される場合があります。