Преобразование значений ConfigParser в типы данных python

ConfigParser требует, чтобы все секции, ключи и значения были строками; не удивительно. Он имеет методы для преобразования значений в типы данных с помощью getfloat, getint, getboolean. Если вы не знаете тип данных, вы можете обернуть get() с помощью eval(), чтобы получить оценку строки, например:

>>> from ConfigParser import SafeConfigParser
>>> cp = SafeConfigParser()
>>> cp.add_section('one')
>>> cp.set('one', 'key', '42')
>>> print cp.get('one', 'key')
'42'
>>> print eval(cp.get('one', 'key'))
42
>>> cp.set('one', 'key', 'None')
>>> print eval(cp.get('one', 'key'))
None
>>> 

Есть ли лучший способ? Я предполагаю наличие серьезных проблем с безопасностью при оценке текста из файла, который я признаю; Я полностью доверяю файлу.

Я думал, что для этого я бы использовал pickle, но мне действительно хотелось бы, чтобы файл конфигурации был удобочитаемым.

Как бы вы это сделали?

Ответ 1

Если вы используете Python 2.6 или выше, вы можете использовать ast.literal_eval:

ast.literal_eval (node_or_string)
Безопасно оцените выражение node или строку, содержащую выражение Python. Строка или node может содержать только следующие литературные структуры Python: строки, числа, кортежи, списки, dicts, booleans и None.

Это можно использовать для безопасной оценки строк, содержащих выражения Python, из ненадежных источников без необходимости самостоятельно анализировать значения.

Это будет работать как eval, когда строка будет безопасной:

>>> literal_eval("{'key': 10}")
{'key': 10}

Но это не удастся, если появится что-либо помимо типов, перечисленных в документации:

>>> literal_eval("import os; os.system('rm -rf somepath')")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib64/python2.6/ast.py", line 49, in literal_eval
    node_or_string = parse(node_or_string, mode='eval')
  File "/usr/lib64/python2.6/ast.py", line 37, in parse
    return compile(expr, filename, mode, PyCF_ONLY_AST)
  File "<unknown>", line 1
    import os; os.system('rm -rf somepath')
         ^
SyntaxError: invalid syntax

Ответ 2

Для тех, кто может искать другой более простой ответ, вместо того, чтобы самостоятельно преобразовывать типы данных, вы можете использовать localconfig модуль, который выполняет преобразование для вас. Преобразование выполняется путем угадывания типа данных на основе значения (I.e. 123 - это int, 123.4 - float, true - bool и т.д.).

Вот пример, следующий за OP:

>>> from localconfig import config
>>> config.read('[one]\nkey = 42\nkey2 = None')
>>> config.one.key, type(config.one.key)
(42, <type 'int'>)
>>> config.one.key2, type(config.one.key2)
(None, <type 'NoneType'>)
>>> config.get('one', 'key'), config.get('one', 'key2')
(42, None)

Это оболочка поверх ConfigParser, поэтому она полностью совместима.

Проверьте это на https://pypi.python.org/pypi/localconfig

Ответ 3

Если вы находитесь на 2.7+, вы можете использовать методы .getint .getfloat .getbool. Подробнее о них вы можете узнать в docs

Таким образом, ваше приложение будет использовать print cp.getint('one', 'key')