#python #eval #configparser
#python #eval #configparser
Вопрос:
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)
Безопасно вычисляйте узел выражения или строку, содержащую выражение Python. Предоставленная строка или узел могут состоять только из следующих литеральных структур Python: строк, чисел, кортежей, списков, dicts, логических значений и 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
Комментарии:
1. я использовал ваш ответ для создания этого: codereview.stackexchange.com/questions/2775 /…
Ответ №2:
Для тех, кто, возможно, ищет другой более простой ответ, вместо того, чтобы самостоятельно преобразовывать типы данных, вы можете использовать модуль localconfig, который выполняет преобразование за вас. Преобразование выполняется путем угадывания типа данных на основе значения (т.е. 123 — это int, 123.4 — это float, true — это bool и так далее).
Вот пример, следующий за OP:
>>> from localconfig import config
>>> config.read('[one]nkey = 42nkey2 = 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
Комментарии:
1. Спасибо, ваши пакеты были очень полезны для меня!
Ответ №3:
Вот еще одно решение. Вы можете сгенерировать getany()
метод, который автоматически определит и вернет правильный тип данных для большинства типов, включая str
, int
, float
bool
и None
.
Обратите внимание, что для этого обозначения в файле конфигурации должны быть Python. например, True
для логических значений true и None
для значений null.
from ast import literal_eval
import configparser
parser = configparser.ConfigParser(converters={"any": lambda x: literal_eval(x)})
value = parser.getany("section", "key")
# ...
Ответ №4:
Если вы используете версию 2.7 , вы можете использовать .getint
.getfloat
.getbool
методы. Вы можете узнать больше о них в документах
Таким образом, ваше приложение будет использовать print cp.getint('one', 'key')
Ответ №5:
Проверьте ConfigIt для получения дополнительных параметров конфигурации pythonic