Списки в ConfigParser
Типичный сгенерированный файл ConfigParser выглядит так:
[Section]
bar=foo
[Section 2]
bar2= baz
Теперь, есть ли способ индексировать списки, например:
[Section 3]
barList={
item1,
item2
}
Связанный вопрос: Уникальные ключи Pythons ConfigParser для каждого раздела
Ответы
Ответ 1
Нет ничего, что помешало бы вам упаковать список в строку с разделителями и распаковать его, как только вы получите строку из конфига. Если вы сделали это так, ваш раздел конфигурации выглядел бы следующим образом:
[Section 3]
barList=item1,item2
Это не очень, но функционально для большинства простых списков.
Ответ 2
Также немного поздно, но, возможно, полезно для некоторых.
Я использую комбинацию 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] очень удобен.
Ответ 3
Поздняя вечеринка, но недавно я реализовал это с выделенным секцией в файле конфигурации для списка:
[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
Надеюсь, что это поможет другим людям Googling этот вопрос;)
Ответ 4
Одна вещь, о которой многие люди не знают, это то, что допустимы многострочные значения конфигурации. Например:
;test.ini
[hello]
barlist =
item1
item2
Теперь значение config.get('hello','barlist')
будет:
"\nitem1\nitem2"
который вы легко можете разделить на метод разделенных линий (не забудьте фильтровать пустые элементы).
Если мы посмотрим на большую структуру, такую как Pyramid, они используют эту технику:
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)]
Обратите внимание, что при использовании этого метода есть несколько вещей, которые нужно учитывать
- Новые строки, которые являются элементами, должны начинаться с пробелов (например, пробела или вкладки)
- Все следующие строки, начинающиеся с пробелов, считаются частью предыдущего элемента. Также, если у него есть знак = или он начинается с; следуя пробелу.
Ответ 5
Если вы хотите передать буквально в список, вы можете использовать:
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"]
Ответ 6
Я приземлился здесь, пытаясь уничтожить это...
[global]
spys = [email protected], [email protected]
Ответ состоит в том, чтобы разбить его на запятую и разбить пробелы:
SPYS = [e.strip() for e in parser.get('global', 'spys').split(',')]
Чтобы получить результат списка:
['[email protected]', '[email protected]']
Он может не отвечать на вопрос OP точно, но может быть простым ответом, который ищут некоторые люди.
Ответ 7
Никакое упоминание о 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
.
Ответ 8
Это то, что я использую для списков:
содержимое файла конфигурации:
[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]
спасибо.
Ответ 9
Поддерживаются только примитивные типы для сериализации с помощью парсер-конфигурации. Я бы использовал JSON или YAML для такого рода требований.
Ответ 10
Я столкнулся с той же проблемой в прошлом. Если вам нужны более сложные списки, подумайте о создании собственного анализатора, наследуя его от 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
С помощью этого решения вы также сможете определить словари в вашем файле конфигурации.
Но будьте осторожны! Это не так безопасно: это означает, что любой может запустить код через ваш файл конфигурации. Если безопасность не является проблемой в вашем проекте, я бы рассмотрел возможность использования непосредственно классов python в качестве файлов конфигурации. Ниже приведено гораздо более мощное и затратное время, чем файл ConfigParser:
class Section
bar = foo
class Section2
bar2 = baz
class Section3
barList=[ item1, item2 ]
Ответ 11
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'
Это очень быстрый синтаксический анализ простых конфигураций, вы теряете все возможности для извлечения ints, bools и других типов вывода без преобразования объекта, возвращенного из Parser
, или повторного выполнения задания синтаксического анализа, выполняемого Parser класс в другом месте.
Ответ 12
json.loads
& ast.literal_eval
кажется, работает, но простой список в конфигурации обрабатывает каждый символ как байт, возвращая даже квадратную скобку....
то есть если в config есть значение fieldvalue = [1,2,3,4,5]
затем config.read(*.cfg)
config['fieldValue'][0]
возвращая [
вместо 1
Ответ 13
Я выполнил аналогичную задачу в своем проекте с разделом с ключами без значений:
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(self.config['FEATURES'].keys())
print(features)
Выход:
['BIOtag', 'TextPosition', 'IsNoun', 'IsNomn']
app.config:
[FEATURES]
BIOtag
TextPosition
IsNoun
IsNomn