[英]Lists in ConfigParser
典型的 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
希望这有助于其他人在谷歌上搜索这个问题;)
很多人不知道的一件事是允许多行配置值。 例如:
;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"]
在这些答案中没有提到ConfigParser()
的converters
kwarg是相当令人失望的。
根据文档,您可以将字典传递给ConfigParser
,该字典将为解析器和部分代理添加一个get
方法。 所以对于一个列表:
例子.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
解释的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 的问题,但可能是某些人正在寻找的简单答案。
这是我用于列表的内容:
配置文件内容:
[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]
谢谢。
我在我的项目中完成了类似的任务,其中包含没有值的键:
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']
应用程序配置:
[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn
所以我更喜欢的另一种方法是拆分值,例如:
#/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 ]
如果这是您的 config.ini:
[Section 3]
barList=item1,item2
然后使用 configparser 你可以这样做:
from configparser import ConfigParser
config = ConfigParser()
config.read('config.ini')
my_list = config['Section 3']['barList'].split(',')
你会得到:
my_list = ['item1', 'item2']
split() 方法将返回一个列表,请参阅 Python 字符串文档。
如果您的 config.ini 中有空格,如下所示:
[Section 3]
barList= item1, item2
那你最好这样做:
my_list = [x.strip() for x in config['Section 3']['barList'].split(',')]
如果您的项目是数字(例如整数),只需应用:
my_list_of_ints = list(map(int, my_list))
你会得到:
my_list_of_ints = [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 类在其他地方完成的解析工作。
json.loads
& ast.literal_eval
似乎正在工作,但配置中的简单列表将每个字符视为字节,因此甚至返回方括号....
意思是如果配置有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 文档字符串中读取的那样:
值可以跨越多行,只要它们比值的第一行缩进得更深。 根据解析器的模式,空行可能被视为多行值的一部分或被忽略。
您可以在配置文件中使用列表,然后在 python 中解析它
from ast import literal_eval
literal_eval("[1,2,3,4]")
import json
json.loads("[1,2,3,4]")
您也可以在配置文件后面使用 json 文件,如下所示:
your config file :
[A]
json_dis = .example.jason
--------------------
your code :
import configparser
config = configparser.ConfigParser()
config.read('config.ini')
# getting items of section A
config.items('A')
# result is a list of key-values
为了让 Grr 的答案(我最喜欢的)更进一步,您可以使用 map 函数,而不是在 .ini 文件中用引号将列表项括起来。 这允许您以 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']
对 split(',') 的改进可能是将逗号分隔值视为 CSV 文件中的记录
import csv
my_list = list(csv.reader([config['Section 3']['barList']], dialect=csv.excel))[0]
您可以配置方言来解析您喜欢的任何 CSV 样式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.