Как использовать ConfigParser для извлечения неизвестного количества пар значений?
В этом вопросе OP хотел извлечь неизвестное количество разделов из файла конфигурации, используя ConfigParser, где все разделы имели один и тот же внутренний формат.
В моем случае я вынужден ограничить все разделы одним разделом. Я пытаюсь разработать поддерживаемый, вменяемый метод хранения "пар" данных. Придуманный пример объяснит лучше:
[pings]
host1 = foo.com
port1 = 80
interval1 = 60
host2 = bar.com
port2 = 8080
interval2 = 300
host3 = baz.com
port3 = 443
interval3 = 15
Это можно прочитать в цикле инкрементного индекса, и как только мы достигнем итерации, где ожидаемое значение не найдено, мы можем предположить, что достигли конца данных и остановились. Проблема в том, что это некрасиво и неустранимо, и, что еще хуже, предположим, что мы хотели закомментировать host1
... Нам нужно изменить нумерацию всего остального в списке, чтобы предотвратить преждевременное завершение сканирования.
Это не кажется мне намного лучше:
[pings]
hosts = foo.com, bar.com, baz.com
ports = 80, 8080, 443
intervals = 60, 300, 15
Слишком трудно читать для любого значительного числа элементов, хрупких для редактирования и т. Д.
Я мог бы повернуть это:
[pings]
ping1 = foo.com, 80, 60
ping2 = bar.com, 8080, 300
ping3 = baz.com, 443, 15
Немного более логически сгруппированы, но все еще страдает от проблемы перенумерации строк, если элементы добавляются / удаляются / переставляются. Также легко потеряться (подумайте, визуально сканируя очень широкую таблицу CSV).
Я хотел бы избежать встраивания JSON или любых формальных литеральных обозначений объектов. Слишком много возможностей для плохого редактирования, чтобы сбить с толку парсер.
Давным-давно я помню работу с PHP, где вы могли добавить переменное количество элементов строки запроса, например ?host[]=foo.com&host[]=bar.com&host[]=baz.com
и $_GET['host']
global станет массивом с тремя элементами внутри. Кража этого синтаксиса, я мог бы сделать:
[pings]
host[] = foo.com
port[] = 80
interval[] = 60
host[] = bar.com
port[] = 8080
interval[] = 300
host[] = baz.com
port[] = 443
interval[] = 15
... или же:
[pings]
ping[] = foo.com, 80, 60
ping[] = bar.com, 8080, 300
ping[] = baz.com, 443, 15
... и было бы немного меньше беспокоиться при добавлении / удалении элементов. Но я верю, что на самом деле случится с ConfigParser, если последние элементы (или это самые ранние?) Перезапишут другие... если []
даже принят в качестве ключа конфигурации.
Существуют ли передовые практики для выражения таких вещей в конфигурационных файлах?
1 ответ
Без тестирования я бы написал что-то вроде:
config = ConfigParser.ConfigParser()
with open('path/to/file.ini') as config_f:
config.readfp(config_f)
# config.readfile in 3.2+
configitems = config.section('pings')
ping_infos = [{'host':host, 'port':port, 'interval':interval} for
host, port, interval in [value.split()]} for
key,value in configitems if key.startswith('ping')]
Затем вы можете написать свой конфигурационный файл как
[pings]
; pingANYUNIQUECHAR = hostname, portnumber, interval
ping-foo.com = foo.com, 80, 60
ping-bar.com = bar.com, 8080, 300
И в итоге вы получите:
ping_infos = [{'host': 'foo.com',
'port': '80',
'interval': 60},
{'host': 'bar.com',
'port': 8080,
'interval': 300}]