Списки в ConfigParser - PullRequest
       61

Списки в ConfigParser

145 голосов
/ 03 декабря 2008

Типичный файл, сгенерированный ConfigParser, выглядит так:

[Section]
bar=foo
[Section 2]
bar2= baz

Теперь, есть ли способ индексировать списки, например:

[Section 3]
barList={
    item1,
    item2
}

Смежный вопрос: Уникальные ключи Python ConfigParser для каждого раздела

Ответы [ 12 ]

184 голосов
/ 16 марта 2012

Также немного поздно, но, возможно, полезно для некоторых. Я использую комбинацию 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] очень удобным.

114 голосов
/ 03 декабря 2008

Ничто не мешает вам упаковать список в строку с разделителями, а затем распаковать его, как только вы получите строку из конфигурации. Если вы сделаете это так, ваш раздел конфигурации будет выглядеть так:

[Section 3]
barList=item1,item2

Это не красиво, но функционально для большинства простых списков.

87 голосов
/ 08 ноября 2011

Опаздывает на эту вечеринку, но недавно я реализовал это с выделенным разделом в файле конфигурации для списка:

[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

Надеюсь, это поможет другим людям, погуглив этот вопрос;)

57 голосов
/ 08 августа 2012

Многие люди не знают, что допустимы многострочные значения конфигурации. Например:

;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. Все последующие строки, начинающиеся с пробела, считаются частью предыдущего элемента. Также, если он имеет знак = или если он начинается с; после пробела.
31 голосов
/ 18 марта 2014

Если вы хотите буквально передать список, вы можете использовать:

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"]
15 голосов
/ 27 марта 2014

Я приземлился здесь в поисках этого ...

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

Возможно, он не дает точного ответа на вопрос ОП, но может быть простым ответом, который ищут некоторые люди.

9 голосов
/ 13 ноября 2018

Никаких упоминаний о 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 голосов
/ 13 мая 2015

Это то, что я использую для списков:

содержимое файла конфигурации:

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

спасибо.

2 голосов
/ 03 декабря 2008

Я сталкивался с той же проблемой в прошлом. Если вам нужны более сложные списки, рассмотрите возможность создания собственного синтаксического анализатора путем наследования от 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 ]
2 голосов
/ 03 декабря 2008

Для сериализации в конфигурационном парсере поддерживаются только примитивные типы. Я бы использовал JSON или YAML для такого рода требований.

...