복붙노트

[PYTHON] 동일한 키에 대해 여러 값을 유지하면서 파일을 구성하는 방법은 무엇입니까?

PYTHON

동일한 키에 대해 여러 값을 유지하면서 파일을 구성하는 방법은 무엇입니까?

ConfigParser를 사용하여 동일한 키에 대해 여러 값을 읽을 수 있어야합니다. 구성 파일 예제 :

[test]
foo = value1
foo = value2
xxx = yyy

ConfigParser를 '표준'으로 사용하면 값이 value2 인 키 foo가 하나 있습니다. 하지만 파서가 두 값을 모두 읽어야합니다.

중복 키에 대한 항목 다음에 다음 예제 코드를 작성했습니다.

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 포함)은 config 파일에서 'ordinary'를 읽으며 foo (다른 값을 덮어 쓰거나 삭제)의 값으로 value2 만 남겨두고 다음과 같은 예상 결과를 얻습니다.

value2
yyy

두 번째 부분 (config2) 내 접근 방식을 사용하여 목록에 여러 값을 추가하지만 출력 대신

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

반복되는 값을 제거하려면 어떻게해야합니까? 출력을 다음과 같이 예상합니다.

['value1', 'value2']
yyy

또는

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

(나는 모든 가치가 목록에 있다면 상관 없다 ...). 어떤 제안이라도 환영합니다.

해결법

  1. ==============================

    1.작은 수정을 통해, 나는 당신이 원하는 것을 얻을 수있었습니다 :

    작은 수정을 통해, 나는 당신이 원하는 것을 얻을 수있었습니다 :

    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']
    
  2. ==============================

    2.허용 된 응답은 config.sections ()를 깨고 항상 빈 목록 (Python 3.5.3에서 테스트 됨)을 반환합니다. super () .__ setitem __ (key, value)에 의해 super (OrderedDict, self) .__ setitem __ (key, value)를 대체하지만, 이제는 config.get (section, key)가 더 이상 문자열 목록이 아닌 연결된 문자열을 반환합니다.

    허용 된 응답은 config.sections ()를 깨고 항상 빈 목록 (Python 3.5.3에서 테스트 됨)을 반환합니다. super () .__ setitem __ (key, value)에 의해 super (OrderedDict, self) .__ 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
    
  3. ==============================

    3.@ abarnert의 대답으로 약간 변경됩니다. 그렇지 않으면 __setitem__을 반복적으로 호출하고 어떤 이유로 중지되지 않습니다.

    @ abarnert의 대답으로 약간 변경됩니다. 그렇지 않으면 __setitem__을 반복적으로 호출하고 어떤 이유로 중지되지 않습니다.

    이 파일 :

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

    파이썬 :

    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'])
    
  4. ==============================

    4.더 많은 예제 test.cfg의 여러 값.

    더 많은 예제 test.cfg의 여러 값.

    [test]
    foo = value1
    foo = value2
     value3
    xxx = yyy
    

    value3 식품 목록에 값을 추가합니다.

    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 
    

    변환 전 값은 항상 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')]
    
  5. from https://stackoverflow.com/questions/15848674/how-to-configparse-a-file-keeping-multiple-values-for-identical-keys by cc-by-sa and MIT license