Используйте 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"))))

Конечно, вы все равно рискуете уничтожить ваш экземпляр класса, переопределив ключи, которые не должны быть переопределены.

Другие вопросы по тегам