Я использую библиотеку configparser в python для управления файлами конфигурации.
Но я не могу найти метод для хранения и извлечения структуры данных кортежей через него.
Мои данные - это словарь кортежей.
name_mapper = {
0 = (0, 0)
1 = (0, 1)
2 = (0, 2)
3 = (1, 0)
4 = (1, 1)
5 = (1, 2)
6 = (2, 0)
7 = (2, 1)
8 = (2, 2)
9 = (3, 0)
10 = (3, 1)
11 = (3, 2)
}
Когда я пишу этот словарь через configparser, все становится строкой.
myconfig.ini
[NAME_MAPPER]
0 = (0, 0)
1 = (0, 1)
2 = (0, 2)
3 = (1, 0)
4 = (1, 1)
5 = (1, 2)
6 = (2, 0)
7 = (2, 1)
8 = (2, 2)
9 = (3, 0)
10 = (3, 1)
11 = (3, 2)
Теперь при чтении "my_config.ini"
config = configparser.ConfigParser()
config.read('config_params.ini')
name_mapper = dict(config['NAME_MAPPER'])
Но словарь больше не содержит кортежи, это просто кортеж, отформатированный как строка.
name_mapper = {
'0' = '(0, 0)'
'1' = '(0, 1)'
'2' = '(0, 2)'
'3' = '(1, 0)'
'4' = '(1, 1)'
'5' = '(1, 2)'
'6' = '(2, 0)'
'7' = '(2, 1)'
'8' = '(2, 2)'
'9' = '(3, 0)'
'10' = '(3, 1)'
'11' = '(3, 2)'
}
Я нашел способ исправить это, используя метод ast.literal_eval.
from ast import literal_eval
new_name_mapper = dict()
for each in name_mapper:
new_name_mapper[int(each)] = literal_eval(name_mapper[each])
Теперь new_name_mapper правильно отформатирован.
name_mapper = {
0 = (0, 0)
1 = (0, 1)
2 = (0, 2)
3 = (1, 0)
4 = (1, 1)
5 = (1, 2)
6 = (2, 0)
7 = (2, 1)
8 = (2, 2)
9 = (3, 0)
10 = (3, 1)
11 = (3, 2)
}
Но я уверен, что это не лучший подход. Кто-нибудь получил лучше и больше питонических идей.
Парсер конфигурации всегда будет возвращать строки, если только вы не используете явный преобразователь с помощью методов getbool
getint``etc. Однако вы можете написать свою собственную функцию конвертера и зарегистрировать ее в своем синтаксическом анализаторе, а затем использовать ее для извлечения значения любым удобным для вас способом.
Из Документация по конфигурационному синтаксическому анализатору:
converters, default value: not set
Config parsers provide option value getters that perform type conversion. By default getint(), getfloat(), and getboolean() are implemented. Should other getters be desirable, users may define them in a subclass or pass a dictionary where each key is a name of the converter and each value is a callable implementing said conversion. For instance, passing {'decimal': decimal.Decimal} would add getdecimal() on both the parser object and all section proxies. In other words, it will be possible to write both parser_instance.getdecimal('section', 'key', fallback=0) and parser_instance['section'].getdecimal('key', 0).
If the converter needs to access the state of the parser, it can be implemented as a method on a config parser subclass. If the name of this method starts with get, it will be available on all section proxies, in the dict-compatible form (see the getdecimal() example above).
Таким образом, вы можете написать функцию для разбора кортежа
>>> def parse_tuple(input):
... return tuple(k.strip() for k in input[1:-1].split(','))
>>> parse_tuple('(1, 2, 3)')
>>> ('1', '2', '3')
или если вам нужны целые числа:
>>> def parse_int_tuple(input):
... return tuple(int(k.strip()) for k in input[1:-1].split(','))
>>> parse_int_tuple('(1, 2, 3)')
>>> (1, 2, 3)
создайте свой объект configparser, передав этот преобразователь:
>>> parser = ConfigParser(converters = {'tuple': parse_int_tuple})
>>> parser.read_dict({'NAME_MAPPER': name_mapper})
>>> parser['NAME_MAPPER'].gettuple('0')
(0, 0)
IMO, это самый подход питонический, поскольку он использует только хорошо документированные функции.