일반적인 ConfigParser 생성 파일은 다음과 같습니다.
[Section]
bar=foo
[Section 2]
bar2= baz
이제 다음과 같은 목록을 색인화하는 방법이 있습니까?
[Section 3]
barList={
item1,
item2
}
관련 질문 : 섹션 당 Python의 ConfigParser 고유 키
일반적인 ConfigParser 생성 파일은 다음과 같습니다.
[Section]
bar=foo
[Section 2]
bar2= baz
이제 다음과 같은 목록을 색인화하는 방법이 있습니까?
[Section 3]
barList={
item1,
item2
}
관련 질문 : 섹션 당 Python의 ConfigParser 고유 키
답변:
목록을 구분 된 문자열로 포장 한 다음 구성에서 문자열을 얻으면 압축을 풀지 않습니다. 이 방법으로 설정하면 구성 섹션은 다음과 같습니다.
[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] 섹션이 매우 편리합니다.
key5 : [r"abc $x_i$", r"def $y_j$"]
합니까? 그들은 오류를 제기json.decoder.JSONDecodeError: Expecting value: line 1 column 2 (char 1)
이 파티에 늦었지만 최근에는 구성 파일의 전용 섹션으로 목록을 구현했습니다.
[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
희망이 다른 사람들 이이 질문을 인터넷 검색하는 데 도움이되기를 바랍니다)
; comment
을 다시 작성하지 않고도 목록에서 특정 항목을 제거 할 수 있기 때문에이 솔루션이 마음 에 듭니다.
key
ConfigParser가 이러한 모든 키를 소문자로 변환
config = ConfigParser.SafeConfigParser()
config.optionxform = str
그러면 사건은 혼자 남게됩니다
많은 사람들이 모르는 것 중 하나는 여러 줄 구성 값이 허용된다는 것입니다. 예를 들면 다음과 같습니다.
;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)]
이 기술을 사용할 때주의해야 할 사항이 몇 가지 있습니다.
.splitlines()
대신에 사용 .split()
합니까? 각각의 기본 동작을 사용하면 분할이 분명히 우수합니다 (빈 줄을 필터링 함). 내가 뭔가를 놓치지 않으면 ...
당신이 할 경우 말 그대로 목록을 전달 당신은 사용할 수 있습니다 :
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()
있습니까? 후자가 더 많은 보안을 제공한다고 생각합니다.
이 답변 중 하나 에 대한 converters
kwarg에 대한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
.
나는 이것을 소비하려고 여기에 도착했다 ...
[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의 질문에 정확하게 대답하지는 않지만 일부 사람들이 찾고있는 간단한 답변 일 수 있습니다.
sorger@espionage.su
! 내 메일이 계속 수신 거부되는 것은 당연합니다! > _ <
그래서 내가 선호하는 다른 방법은 예를 들어 값을 나누는 것입니다.
#/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
이 솔루션을 사용하면 구성 파일에서 사전을 정의 할 수도 있습니다.
그러나 조심하십시오! 이것은 안전하지 않습니다. 즉, 누구나 구성 파일을 통해 코드를 실행할 수 있습니다. 프로젝트에서 보안이 문제가되지 않으면 직접 파이썬 클래스를 구성 파일로 사용하는 것이 좋습니다. 다음은 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(',')
것을 맹목적으로 분석 하지 않는 이유는 무엇입니까?
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 및 기타 유형의 출력을 가져올 수있는 모든 기능을 잃어 버립니다 .
값이없는 키가있는 섹션으로 프로젝트에서 비슷한 작업을 완료했습니다.
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
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 문자열에서 읽은 것처럼 :
값의 첫 줄보다 깊게 들여 쓰기 만하면 값이 여러 줄에 걸쳐있을 수 있습니다. 파서의 모드에 따라 빈 줄은 여러 줄 값의 일부로 취급되거나 무시 될 수 있습니다.