ConfigParser生成的典型文件如下所示:
[Section]
bar=foo
[Section 2]
bar2= baz
现在,有没有一种方法来索引列表,例如:
[Section 3]
barList={
item1,
item2
}
相关问题:Python的ConfigParser每个节的唯一键
ConfigParser生成的典型文件如下所示:
[Section]
bar=foo
[Section 2]
bar2= baz
现在,有没有一种方法来索引列表,例如:
[Section 3]
barList={
item1,
item2
}
相关问题:Python的ConfigParser每个节的唯一键
当前回答
这些回答中没有提到ConfigParser()的转换器kwarg,这令人相当失望。
根据文档,您可以向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解释的列表。
其他回答
对split(',')的改进可能是将逗号分隔的值视为CSV文件中的一条记录
import csv
my_list = list(csv.reader([config['Section 3']['barList']], dialect=csv.excel))[0]
您可以配置一种方言来解析任何您喜欢的CSV样式。
很多人不知道的一件事是允许多行配置值。例如:
;test.ini
[hello]
barlist =
item1
item2
config.get('hello','barlist')的值现在将是:
"\nitem1\nitem2"
你可以很容易地用splitlines方法进行分割(不要忘记过滤空项)。
如果我们看看像金字塔这样的大框架,他们正在使用这种技术:
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)]
注意,在使用这种技术时需要注意一些事情
作为项目的新行应该以空格开始(例如空格或制表符) 下面所有以空格开头的行都被认为是前一项的一部分。如果它有一个=号或者如果它以a开头;跟着空格。
我使用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完成了类似的任务:
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
正如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)
请记住缩进的重要性。ConfigParser文档字符串: 值可以跨越多行,只要它们缩进得更深 而不是第一行的值。根据解析器的模式,为空白 行可以被视为多行值的一部分或被忽略。