ConfigParser의 목록


답변:


142

목록을 구분 된 문자열로 포장 한 다음 구성에서 문자열을 얻으면 압축을 풀지 않습니다. 이 방법으로 설정하면 구성 섹션은 다음과 같습니다.

[Section 3]
barList=item1,item2

예쁘지는 않지만 가장 간단한 목록에는 작동합니다.


2
복잡한 목록이 있으면이 질문을 참조 할 수 있습니다. stackoverflow.com/questions/330900/… :-)
John Fouhy

좋은 해결책이지만 가능한 구분 기호가 없으면 목록 항목 안에 표시되지 않을 것입니다. ??
wim

@wim 내 대답을 참조하십시오. \ n을 구분 기호로 사용할 수 있습니다
Peter Smit

@wim 올바른 문자가 될 수있는 경우 구분 문자를 이스케이프 처리하는 방법을 구현해야합니다. (그리고 탈출을 위해 사용하는 캐릭터를 피할 수있는 방법입니다.)
jamesdlin

목록에 단일 요소가 있으면 어떻게됩니까?
Sérgio Mafra

223

또한 약간 늦었지만 일부에게는 도움이 될 수 있습니다. 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] 섹션이 매우 편리합니다.


1
값을 자동으로 "캐스트"하므로 미리 유형을 모르는 경우 유용 할 수 있습니다.
LeGBT

나는이 아이디어를 좋아하지만 숫자 목록으로 만 작동시킬 수 있습니다. 따옴표는 도움이되지 않습니다. 기묘한. 계속합니다.
rsaw

5
문자열이 작동하려면 [ "a", "b", "c"]가 있어야합니다. 나에게 이것은 숫자를 클릭하지만 cfg 파일은 대부분 편집 가능하기 때문에 매번 ""를 추가하는 것은 고통 스럽다. 차라리 쉼표를 사용하고 나눕니다.
Saurabh Hirani 2016

표준 라이브러리 만 사용하는 우아한 솔루션입니다. 의견과 json을 사용할 수있어서 좋습니다.
wi1

원시 문자열에 대해 어떻게 작동 key5 : [r"abc $x_i$", r"def $y_j$"]합니까? 그들은 오류를 제기json.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
kingusiu

101

이 파티에 늦었지만 최근에는 구성 파일의 전용 섹션으로 목록을 구현했습니다.

[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

희망이 다른 사람들 이이 질문을 인터넷 검색하는 데 도움이되기를 바랍니다)


3
전체 솔루션 ; comment을 다시 작성하지 않고도 목록에서 특정 항목을 제거 할 수 있기 때문에이 솔루션이 마음 에 듭니다.
wim

1
+1, 그러나이 작업을 수행하는 경우 keyConfigParser가 이러한 모든 키를 소문자로 변환
Alex Dean

4
@AlexDean optionxform = str을 설정하여 camelCase를 그대로 두도록 ConfigParser를 설정할 수 있습니다. 예 : config = ConfigParser.SafeConfigParser() config.optionxform = str 그러면 사건은 혼자 남게됩니다
Cameron Goodale

@Henry Cooke 키가 여러 번 나열 될 때 테스트 했습니까?
DevPlayer

1
@DevPlayer 다중 키 사용법을 사용하면 마지막 값만 얻습니다. (다른 독자의 이익을 위해 2 년 전의 의견에 응답)
Marcin K

63

많은 사람들이 모르는 것 중 하나는 여러 줄 구성 값이 허용된다는 것입니다. 예를 들면 다음과 같습니다.

;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)]

이 기술을 사용할 때주의해야 할 사항이 몇 가지 있습니다.

  1. 항목 인 줄 바꿈은 공백으로 시작해야합니다 (예 : 공백 또는 탭).
  2. 공백으로 시작하는 다음 줄은 모두 이전 항목의 일부로 간주됩니다. 또한 = 기호가 있거나;로 시작하는 경우; 공백을 따르십시오.

.splitlines()대신에 사용 .split()합니까? 각각의 기본 동작을 사용하면 분할이 분명히 우수합니다 (빈 줄을 필터링 함). 내가 뭔가를 놓치지 않으면 ...
rsaw

7
.split ()은 모든 공백에서 분리되고 (특정 문자가 제공되지 않은 경우), .splitlines ()는 모든 개행 문자에서 분리됩니다.
Peter Smit

아 좋은 지적이다. 내 가치 중 어느 것도 공백이 없기 때문에 나는 그것에 대해 생각하지 않았습니다.
rsaw

38

당신이 할 경우 말 그대로 목록을 전달 당신은 사용할 수 있습니다 :

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"]

이 경우 ast.literal_eval()(아마도 더 널리 사용되는) 사용 을 비교할 때 사용 하면 어떤 이점이 json.loads()있습니까? 후자가 더 많은 보안을 제공한다고 생각합니다.
RayLuo

2
나는 이것의 예를보고 싶고, 당신이 당신의 의견이 그 자체로 좋은 질문을 할지라도 도움이 될 것이라고 생각되면이 스레드에 대한 답변을 자유롭게 추가하십시오. 내가 준 대답은 ConfigParser에서 목록 사용을 단순화하므로 정규식 사용의 복잡성을 제거하는 응용 프로그램 내부에 있습니다. 나는 문맥없이 "보안"가치에 대해 언급 할 수 없었다.
PythonTester

= 또는 다음에 파이썬 문자열이 필요한 literal_eval을 사용하면주의를 기울일 것입니다. 따라서 더 이상 사용할 수 없습니다. 예 : path1 = / some / path / 그러나 path1 = '/ some / path /'
vldbnc

21

이 답변 중 하나 에 대한 converterskwarg에 대한ConfigParser() 언급 은 오히려 실망 스럽습니다.

문서에 따르면 파서 및 섹션 프록시 모두 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 .


15

나는 이것을 소비하려고 여기에 도착했다 ...

[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의 질문에 정확하게 대답하지는 않지만 일부 사람들이 찾고있는 간단한 답변 일 수 있습니다.


2
나는 Dick이 있다고 생각했다 sorger@espionage.su! 내 메일이 계속 수신 거부되는 것은 당연합니다! > _ <
Augusta

1
4 년 후이 의견을 읽고 이스터 에그 (Easter Egg)를 꽉 쥐며
호기심 많은 엔지니어

11

이것이 내가 목록에 사용하는 것입니다.

구성 파일 내용 :

[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]

감사.


이것은 내가 실제로 찾고있는 것입니다 @LittleEaster
ashley

5

그래서 내가 선호하는 다른 방법은 예를 들어 값을 나누는 것입니다.

#/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으로로드하기 위해 값을 대괄호로 묶지 않아도됩니다.


안녕 미치, 후자의 경우 루프하는 동안 명시 적으로 int로 변환하는 대신 get_int ( 'first_row'). split ( ',')을 사용하는 것이 더 좋지 않을까요?
귀도

2

구성 파서에 의한 직렬화에는 기본 유형 만 지원됩니다. 그런 종류의 요구 사항에 JSON 또는 YAML을 사용합니다.


설명해 주셔서 감사합니다. utku. 유일한 문제는 현재 외부 패키지를 사용할 수 없다는 것입니다. 나는 이것을 처리하기 위해 간단한 클래스를 작성할 것이라고 생각합니다. 결국 공유하겠습니다.
pistacchio

어떤 버전의 Python을 사용하고 있습니까? JSON 모듈은 2.6에 포함되어 있습니다.
패트릭 해링턴

2

나는 과거에도 같은 문제에 직면했다. 더 복잡한 목록이 필요한 경우 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

이 솔루션을 사용하면 구성 파일에서 사전을 정의 할 수도 있습니다.

그러나 조심하십시오! 이것은 안전하지 않습니다. 즉, 누구나 구성 파일을 통해 코드를 실행할 수 있습니다. 프로젝트에서 보안이 문제가되지 않으면 직접 파이썬 클래스를 구성 파일로 사용하는 것이 좋습니다. 다음은 ConfigParser 파일보다 훨씬 강력하고 소모적입니다.

class Section
    bar = foo
class Section2
    bar2 = baz
class Section3
    barList=[ item1, item2 ]

그러나이 작업을 생각하고 있습니다. 구성 값을 설정 barList=item1,item2한 다음 호출 if value.find(',') > 0: return value.split(',')하거나 더 나은 방법으로 응용 프로그램이 모든 구성 옵션을 목록으로 구문 분석하고 모든 .split(',')것을 맹목적으로 분석 하지 않는 이유는 무엇입니까?
Droogans

1
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하거나 파서 클래스가 수행 한 파싱 작업을 다시 수행 하지 않고 int, bool 및 기타 유형의 출력을 가져올 수있는 모든 기능을 잃어 버립니다 .


1

값이없는 키가있는 섹션으로 프로젝트에서 비슷한 작업을 완료했습니다.

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

0

json.loads & ast.literal_eval 작동하는 것처럼 보이지만 구성 내 간단한 목록은 각 문자를 바이트로 취급하므로 대괄호조차 반환합니다.

설정에 의미가있는 경우 fieldvalue = [1,2,3,4,5]

다음 config.read(*.cfg) config['fieldValue'][0]반환 [대신에1


0

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)

P 는 들여 쓰기의 중요성을 명심하십시오. ConfigParser doc 문자열에서 읽은 것처럼 :

값의 첫 줄보다 깊게 들여 쓰기 만하면 값이 여러 줄에 걸쳐있을 수 있습니다. 파서의 모드에 따라 빈 줄은 여러 줄 값의 일부로 취급되거나 무시 될 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.