2013-04-06 22 views
11

我需要能夠使用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)使用我的方法進行多值追加到李st,但輸出反而是

['value1', 'value2', 'value1\nvalue2'] 
['yyy', 'yyy'] 

如何擺脫重複值?我如下預期輸出:

['value1', 'value2'] 
yyy 

['value1', 'value2'] 
['yyy'] 

(如果每個值是在列表中,我不介意......)。歡迎任何建議。

回答

11

一個小的修改之後,我是能夠實現你想要什麼:

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'] 
+0

我不知道爲什麼'超(OrderedDict,個體經營)'的作品,但不是'超(MultiOrderedDict,個體經營)'。 – 2013-04-06 09:22:50

+0

是的,完美!除了「超級」異常。也許它*是* OrderedDict'的基類然後... – Alex 2013-04-06 09:43:50

+0

當只有一個值時,有什麼辦法可以讓這個返回一個單值而不是一個列表? ['value1','value2']和yyy而不是['yyy'] – 2014-02-20 12:00:59

-3

更多的例子在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轉換之前始終是列表或字典(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')] 
0

只需稍微改變一下@abarnert's answer,否則它遞歸地調用__setitem__,並且不會由於某種原因而停止。

ini文件:

[section] 
key1 = value1 
key2[] = value21 
key2[] = value22 

的Python:

class MultiOrderedDict(OrderedDict): 
    LIST_SUFFIX = '[]' 
    LIST_SUFFIX_LEN = len(LIST_SUFFIX) 

    def __setitem__(self, key, value): 
     if key.endswith(self.LIST_SUFFIX): 
      values = super(OrderedDict, self).setdefault(key, []) 
      if isinstance(value, list): 
       values.extend(value) 
      else: 
       values.append(value) 
     else: 
      super(MultiOrderedDict, self).__setitem__(key, value) 

    def __getitem__(self, key): 
     value = super(MultiOrderedDict, self).__getitem__(key) 
     if key.endswith(self.LIST_SUFFIX) and not isinstance(value, list): 
      value = value.split('\n') 
     return value 

測試:

def test_ini(self): 
    dir_path = os.path.dirname(os.path.realpath(__file__)) 
    config = RawConfigParser(dict_type=MultiOrderedDict, strict=False) 
    config.readfp(codecs.open('{}/../config/sample.ini'.format(dir_path), encoding="utf_8_sig")) 
    self.assertEquals(config.get("section1", "key1"), 'value1') 
    self.assertEquals(config.get("section1", "key2[]"), ['value21', 'value22']) 
1

接受的答案打破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"] 

的配置INI文件接受重複鍵:

[Section] 
    key = value1 
    key = value2 
+0

我在接受的答案和章節()中修正了錯誤的super()現在有用。 – bernie 2017-10-25 15:47:50

相關問題