我需要能够使用ConfigParser
为同一个键读取多个值。示例配置文件:
[test]
foo = value1
foo = value2
xxx = yyy
使用ConfigParser
的'标准'时,会有一个键foo
,其值为value2
。但我需要解析器读入两个值。
在entry on duplicate key之后,我创建了以下示例代码:
from collections import OrderedDict
from ConfigParser import RawConfigParser
class OrderedMultisetDict(OrderedDict):
def __setitem__(self, key, value):
try:
item = self.__getitem__(key)
except KeyError:
super(OrderedMultisetDict, self).__setitem__(key, value)
return
print "item: ", item, value
if isinstance(value, list):
item.extend(value)
else:
item.append(value)
super(OrderedMultisetDict, self).__setitem__(key, item)
config = RawConfigParser(dict_type = OrderedDict)
config.read(["test.cfg"])
print config.get("test", "foo")
print config.get("test", "xxx")
config2 = RawConfigParser(dict_type = OrderedMultisetDict)
config2.read(["test.cfg"])
print config2.get("test", "foo")
print config.get("test", "xxx")
第一部分(config
)在配置文件中读取'通常',只留下value2
作为foo
的值(覆盖/删除其他值)和我获得以下预期输出:
value2
yyy
第二部分(config2
)使用我的方法将多个值附加到列表中,但输出却是
['value1', 'value2', 'value1\nvalue2']
['yyy', 'yyy']
如何摆脱重复的价值观?我期待输出如下:
['value1', 'value2']
yyy
或
['value1', 'value2']
['yyy']
(我不介意每个值都在列表中......)。欢迎任何建议。
答案 0 :(得分:12)
经过一次小修改,我就能达到你想要的效果:
class MultiOrderedDict(OrderedDict):
def __setitem__(self, key, value):
if isinstance(value, list) and key in self:
self[key].extend(value)
else:
super(MultiOrderedDict, self).__setitem__(key, value)
# super().__setitem__(key, value) in Python 3
config = ConfigParser.RawConfigParser(dict_type=MultiOrderedDict)
config.read(['a.txt'])
print config.get("test", "foo")
print config.get("test", "xxx")
输出:
['value1', 'value2']
['yyy']
答案 1 :(得分:3)
接受的答案会中断config.sections()
,它总是返回一个空列表(使用Python 3.5.3测试)。用super(OrderedDict, self).__setitem__(key, value)
替换super().__setitem__(key, value)
修复了此问题,但现在config.get(section, key)
返回一个连接字符串,不再是字符串列表。
我的解决方案是:
class ConfigParserMultiValues(collections.OrderedDict):
def __setitem__(self, key, value):
if key in self and isinstance(value, list):
self[key].extend(value)
else:
super().__setitem__(key, value)
@staticmethod
def getlist(value):
return value.split(os.linesep)
config = configparser.ConfigParser(strict=False, empty_lines_in_values=False, dict_type=ConfigParserMultiValues, converters={"list": ConfigParserMultiValues.getlist})
...
values = config.getlist("Section", "key") # => ["value1", "value2"]
config INI文件接受重复键:
[Section]
key = value1
key = value2
答案 2 :(得分:1)
在python 3.8中,您还需要添加strict=False
:
class MultiOrderedDict(OrderedDict):
def __setitem__(self, key, value):
if isinstance(value, list) and key in self:
self[key].extend(value)
else:
super().__setitem__(key, value)
config = ConfigParser.RawConfigParser(dict_type=MultiOrderedDict, strict=False)
config.read(['a.txt'])
print config.get("test", "foo")
print config.get("test", "xxx")
答案 3 :(得分:-2)
更多示例test.cfg
中的多个值。
[test]
foo = value1
foo = value2
value3
xxx = yyy
<whitespace>value3
将value3
追加到foo列表。
ConfigParser
将列表转换为字符串。
/usr/lib/python2.7/ConfigParser.pyc in _read(self, fp, fpname)
552 for name, val in options.items():
553 if isinstance(val, list):
--> 554 options[name] = '\n'.join(val)
555
转换前的 value
始终为list或dict(MultiOrderedDict
)。
试试这个 - 用它,config.items
有效:
from collections import OrderedDict
import ConfigParser
class MultiOrderedDict(OrderedDict):
def __setitem__(self, key, value):
if key in self:
if isinstance(value, list):
self[key].extend(value)
return
elif isinstance(value,str):
return # ignore conversion list to string (line 554)
super(MultiOrderedDict, self).__setitem__(key, value)
config = ConfigParser.RawConfigParser(dict_type=MultiOrderedDict)
config.read(['test.cfg'])
print config.get("test", "foo")
print config.get("test", "xxx")
print config.items("test")
输出:
['value1', 'value2', 'value3']
['yyy']
[('foo', ['value1', 'value2', 'value3']), ('xxx', ['yyy'])]
另一项实施MultiOrderedDict
class MultiOrderedDict(OrderedDict):
def __setitem__(self, key, value):
if key in self:
if isinstance(value, list):
self[key].extend(value)
return
elif isinstance(value,str):
if len(self[key])>1:
return
super(MultiOrderedDict, self).__setitem__(key, value)
输出:
['value1', 'value2', 'value3']
yyy
[('foo', ['value1', 'value2', 'value3']), ('xxx', 'yyy')]