Используйте ConfigParser с различными типами переменных в Python
Я пытаюсь использовать ConfigParser
в следующей ситуации. Я бегу некоторый код, после которого у меня есть объект с несколькими атрибутами. Я выбираю некоторые из этих атрибутов и записываю их в .ini
файл с configparser
, Это прекрасно работает и мой .ini
файл выглядит примерно так.
[Section]
path = "D:\\"
number = 10.0
boolean = False
Затем с помощью другого скрипта я хочу прочитать файл и добавить элементы в качестве атрибутов к другому объекту (сам), используя.
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
Это терпит неудачу, потому что все значения читаются как строки configparser, и теперь все атрибуты являются строками. parser.items("Section")
выглядит так:
[('path', '"D:\\"'), ('number', '10.0'), ('boolean', 'False')]
Теперь я мог бы указать и указать значения с плавающей точкой, целые числа и логические значения по их ключам и использовать соответствующие методы. parser.getfloat
, getint
, а также getboolean
чтобы получить правильные типы Python. Однако это означает создание дополнительного списка ключей и цикла для их получения для каждого типа данных, чего я не хочу. Кроме того, даже путь теперь в двойных кавычках, и мне нужно начать удалять кавычки.
Такое поведение делает ConfigParser
почти совершенно бесполезен для меня, и я сомневаюсь, правильно ли я использую его, если ConfigParser
это лучший вариант для моей цели: просто записать атрибуты объекта в файл, а затем прочитать файл и добавить параметры нового объекта в качестве атрибутов. Могу ли я использовать ConfigParser
для этого эффективно? Или я должен начать искать другой метод?
1 ответ
INI - это не JSON. Нет типов данных. Есть разделы и пары ключ / значение. Материал перед =
это ключ, материал после того, как это значение. Все текстовое.
Здесь нет "строк", что означает, что не нужно ничего заключать в двойные кавычки. То же самое касается "сбежавших" обратных слешей. Концепция экранирования не существует в формате файла INI.
Итак, во-первых, ваш файл должен выглядеть так:
[Section]
path = D:\
number = 10.0
boolean = False
Далее я считаю это опасной операцией
parser.read('file.ini')
self.__dict__.update(dict(parser.items("Section")))
потому что он потенциально уничтожает ваш экземпляр класса произвольными значениями из текстового файла, который может содержать мусор, но когда вы можете поклясться, что файл всегда будет в порядке, хорошо, сделайте это, если нужно.
Я бы написал более явный способ чтения и проверки данных конфигурации. Я чувствую вашу причину не делать этого - лень или ложное чувство простоты; обе эти причины не очень хороши.
Если вы хотите полуавтоматический способ преобразования типов, пометьте ключи типом данных.
[Section]
s_path = D:\
f_number = 10.0
b_boolean = False
и написать функцию, которая знает, как с ними обращаться и выбрасывает, когда что-то не так.
def type_convert(items):
result = []
for (key, value) in items:
type_tag = key[:2]
if type_tag == "s_":
result.append((key[2:], value))
elif type_tag == "f_":
result.append((key[2:], float(value)))
elif type_tag == "b_":
result.append((key[2:], bool(value)))
else:
raise ValueError('Invalid type tag "%s" found in ini file.' % type_tag)
# alternatively: "everything else defaults to string"
return result
который вы можете использовать, чтобы сделать операцию несколько более удобной:
self.__dict__.update(dict(type_convert(parser.items("Section"))))
Конечно, вы все равно рискуете уничтожить ваш экземпляр класса, переопределив ключи, которые не должны быть переопределены.