5,1K подписчиков

Пишем Питона на Питоне #2: INI-файл

202 прочитали

Предыдущая часть: Пишем Питона на Питоне!

Может показаться странным, но мы начнём делать игру с загрузки ini-файла. Есть сильное подозрение, что это здорово понадобится в будущем :)

  • Формат ini-файла очень прост и подходит для ручного редактирования. Вы наверняка с ним встречались, а если нет, то можете ознакомиться здесь.
  • Я рассматривал вариант с форматом JSON, но он менее читабелен и его труднее редактировать, поэтому был выбран более простой формат.

В Питоне есть готовый парсер (то есть обработчик) ini-файлов. Это класс ConfigParser в модуле configparser. Но он мне не нравится тем, что для доступа к параметру, допустим, game.speed, надо писать так:

config['game']['speed']

Было бы гораздо лучше писать так:

config.game.speed

Поэтому мы возьмём класс ConfigParser и завернём его в свой класс, который обеспечит нам нужный вид доступа. Заодно мы создадим структуру каталогов проекта и будем размещать разные классы в разных файлах, чтобы у нас всё было как у больших.

Итак, в рабочем каталоге, где вы делаете проект, создайте папку app, а в ней папку utils. В этой папке мы создадим файл config.py cо следующим кодом (ссылка):

Суть нашего класса Config в том, чтобы создать объект класса ConfigParser, загрузить в него файл (filename), и получить готовый к употреблению конфиг (config). Он cостоит из списка секций, а каждая секция содержит список переменных. Всё это, то есть и секции, и переменные в них, нужно взять и сделать свойствами нашего класса.

Для этого мы проходим по списку секций (for section_name in config) и для каждой непустой секции создаём безымянный объект:

section_object = type('', (), {})

Читайте также: ООП в Python: Особенности реализации.

Далее мы проходим уже по секции (for key in section) и найденные пары ключ-значение делаем свойствами (атрибутами) нашего объекта:

setattr(section_object, key, section[key])

Функция setattr(obj, name, value) изменяет в объекте obj свойство с именем name, присваивая ему value. Если такого свойства нет, то оно создаётся. Именно это нам и нужно. В результате, обработав одну секцию, мы получили безымянный объект со свойствами, которые создались из содержимого секции. Теперь весь этот объект мы в свою очередь делаем свойством объекта нашего класса Config:

setattr(self, section_name, section_object)

Всё это происходит при создании объекта. И теперь мы можем писать

config = Config('game.ini')

и далее обращаться к параметрам вроде config.game.speed, и всё будет работать, так как game является атрибутом объекта config, а speed является атрибутом объекта game. Мы их просто создали вручную.

Да, а вот так пока выглядит (исключительно тестовый) файл game.ini (ссылка):

Создайте его в основном каталоге.

Там же создайте файл main.py, где мы проверим работу конфига. В нём пока всего три строчки:

from app.utils.config import Config
config = Config('game.ini')
print(config.game.test)

Сначала мы импортируем собственный класс Config из собственного модуля app.utils.config (помните, что структура каталогов это app/utils).

Затем мы создаём объект класса Config, передав ему в конструктор имя ini-файла (game.ini).

И наконец, мы распечатываем значение config.game.test. Это значит, что в ini-файле должна быть секция с именем game, а в ней должен быть параметр с именем test. И вот значение этого параметра мы и должны получить. Если всё сработало правильно, то после запуска программы будет распечатана строка 'test'. Вы можете изменить ini-файл, задать другие значения параметров или вообще новые параметры, и также попробовать их распечатать.

Следующая часть: Загрузка уровня из файла

Картинка для превью
Картинка для превью