如何在配置解析器 python 中存储和检索元组字典?

How to store and retrieve a dictionary of tuples in config parser python?

我正在使用 python 中的 configparser 库来管理我的配置文件。

但是,我找不到通过它存储和检索元组数据结构的方法。

我的数据是一个元组字典。

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)
}

但我敢肯定,这不是最好的方法。任何人都变得更好和更多 pythonic 创意。

配置解析器将始终 return 字符串,除非您使用 getbool getint`` 等方法使用显式转换器。然而,您可以编写自己的转换器函数并将其注册到您的解析器,然后使用它以您喜欢的任何方式检索值。

来自Configparser Docs

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 这是最 pythonic 的方法,因为它只使用有据可查的功能