Работа с файлами конфигурации в Python: от базовых INI до современных TOML

Раздел: Работа с файлами -> Файловый ввод-вывод

Файлы настроек Python: обзор и варианты реализации

Основной и рекомендуемый способ работы с файлами конфигурации в Python - использование модуля configparser. Он поддерживает формат INI, прост для чтения и записи, не требует установки дополнительных библиотек. Файл настроек обычно имеет расширение .ini или .cfg.


import configparser

config = configparser.ConfigParser()
config.read('settings.ini')

# Чтение значения
db_host = config.get('Database', 'host')
print(db_host)

# Запись с сохранением
config['Database']['port'] = '5432'
with open('settings.ini', 'w') as f:
    config.write(f)
    

ввод программ на python (ввод данных в программе python)

Типичные проблемы и ошибки:

  • Ошибка чтения секции: если секция отсутствует, возникает NoSectionError. Перед доступом проверяйте наличие: if config.has_section('Database').
  • Неверный тип данных: config.get() всегда возвращает строку. Для целых чисел используйте config.getint(), для чисел с плавающей точкой - config.getfloat(), для булевых - config.getboolean().
  • Проблемы с кодировкой: при чтении файла с русскими символами укажите кодировку UTF-8: config.read('settings.ini', encoding='utf-8').

Как использовать JSON для хранения настроек?

JSON - удобный формат, поддерживаемый стандартной библиотекой через модуль json. Подходит для сложных вложенных структур. Однако не поддерживает комментарии.


import json

with open('config.json', 'r') as f:
    config = json.load(f)

print(config['database']['host'])

# Запись изменений
config['database']['port'] = 3306
with open('config.json', 'w') as f:
    json.dump(config, f, indent=4)
    

Python file io (ввод-вывод файлов в python)

Возможные сложности:

  • Повреждённый JSON: json.load() выбросит JSONDecodeError. Всегда оборачивайте в try/except.
  • Необходимость сериализации объектов: JSON поддерживает только базовые типы. Для пользовательских объектов потребуется написать кастомный кодировщик.

Цель: быстрое чтение/запись настроек для веб-приложений или API, где JSON уже является стандартом обмена данными.

Как подключить YAML для более читаемых конфигураций?

YAML - формат с минималистичным синтаксисом, популярен в DevOps. Требует установки библиотеки pyyaml (pip install pyyaml).


import yaml

with open('config.yaml', 'r') as f:
    config = yaml.safe_load(f)

print(config['server']['host'])

# Запись
config['server']['port'] = 8080
with open('config.yaml', 'w') as f:
    yaml.dump(config, f, default_flow_style=False)
    

Python temp files (временные файлы в python)

Типовые ошибки:

  • Использование yaml.load() без аргумента Loader: может привести к выполнению произвольного кода. Всегда применяйте yaml.safe_load().
  • Проблемы с отступами: YAML строг к отступам (пробелы, а не табуляция). Ошибка проявляется как yaml.scanner.ScannerError.
Как работать с настройками в формате TOML?

TOML - современный формат, часто используемый для конфигурации инструментов (pyproject.toml). В Python 3.11+ доступен модуль tomllib, для более старых версий - сторонний tomli или toml.


import tomllib

with open('config.toml', 'rb') as f:
    config = tomllib.load(f)

print(config['app']['version'])

# Запись (требуется библиотека tomli-w)
import tomli_w
config['app']['debug'] = False
with open('config.toml', 'wb') as f:
    tomli_w.dump(config, f)
    

Python index files (индексация файлов в python)

Частые затруднения:

  • Отсутствие поддержки записи в стандартной библиотеке: tomllib предназначен только для чтения. Для записи устанавливайте tomli-w.
  • Неверная структура даты: TOML поддерживает даты/время. При ручном создании файла убедитесь в правильном синтаксисе (ISO 8601).
Как безопасно использовать переменные окружения?

Файлы .env позволяют разделить настройки среды и код. Модуль python-dotenv загружает их в os.environ.


from dotenv import load_dotenv
import os

load_dotenv('.env')
db_password = os.getenv('DB_PASSWORD')
print(db_password)
    

Проблемы:

  • Пути к файлу: по умолчанию load_dotenv() ищет .env в текущей рабочей директории. Для явного указания передавайте полный путь.
  • Не перезаписывает уже существующие переменные: если переменная уже установлена в окружении, load_dotenv() не изменит её (если не указать override=True).

Цель: хранение секретов (пароли, токены) отдельно от кода, особенно в контейнерах или облачных средах.

Для простых проектов можно использовать собственный формат с exec() или eval() - крайне не рекомендуется из-за рисков безопасности. Если такой путь неизбежен, ограничьте доступ к файлу и санируйте содержимое.

- Python config files (конфигурационные файлы в python)
- Python copy file (копирование файла в python)
- Python log file (логирование в файл в python)

Расширенные примеры работы с файлами настроек

Пример

# 1. ConfigParser с секциями и значениями по умолчанию
import configparser

config = configparser.ConfigParser()
config['DEFAULT'] = {
    'server': 'localhost',
    'port': '8080'
}
config['DEFAULT']['timeout'] = '30'

with open('advanced.ini', 'w') as f:
    config.write(f)

# Чтение с fallback
config.read('advanced.ini')
timeout = config.getint('Database', 'timeout', fallback=10)
print(timeout)  # 30, так как есть DEFAULT
30
Пример

# 2. JSON с пользовательскими типами (datetime)
import json
from datetime import datetime

class DateTimeEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

data = {'last_run': datetime.now()}
with open('dates.json', 'w') as f:
    json.dump(data, f, cls=DateTimeEncoder)

with open('dates.json', 'r') as f:
    loaded = json.load(f)
print(loaded['last_run'])
2025-03-30T12:34:56.789012
Пример

# 3. YAML с анкерами и алиасами
import yaml

yaml_text = """
db: &mysql
  host: localhost
  port: 3306
  user: root

production:
  database:
    <<: *mysql
    password: secret

development:
  database:
    <<: *mysql
    password: devpwd
"""

config = yaml.safe_load(yaml_text)
print(config['production']['database']['host'])
print(config['development']['database']['host'])
localhost
localhost
Пример

# 4. TOML с таблицами массивов
import tomllib

data_bytes = b"""
[[servers]]
name = "alpha"
ip = "192.168.1.1"

[[servers]]
name = "beta"
ip = "192.168.1.2"
"""
config = tomllib.loads(data_bytes)
for server in config['servers']:
    print(server['name'], server['ip'])
alpha 192.168.1.1
beta 192.168.1.2
Пример

# 5. .env файл с несколькими строками и комментариями
# Содержимое .env:
# DB_HOST=localhost
# DB_PORT=5432
# # это комментарий
# SECRET=mysecret

from dotenv import load_dotenv
import os

load_dotenv('.env', override=True)
print(os.getenv('DB_HOST'))
print(os.getenv('SECRET'))
localhost
mysecret
Пример

# 6. Сравнение производительности загрузки разных форматов
import timeit
import json, configparser, yaml, tomllib

# Подготовка файлов
data = {'key': 'value', 'nested': {'a': 1}}
with open('test.json', 'w') as f: json.dump(data, f)
with open('test.ini', 'w') as f: f.write('[DEFAULT]\nkey=value\n')
with open('test.yaml', 'w') as f: yaml.dump(data, f)
with open('test.toml', 'wb') as f: 
    f.write(b'key = "value"\n[nested]\na = 1')

def load_json():
    with open('test.json') as f: json.load(f)

def load_ini():
    config = configparser.ConfigParser()
    config.read('test.ini')

def load_yaml():
    with open('test.yaml') as f: yaml.safe_load(f)

def load_toml():
    with open('test.toml', 'rb') as f: tomllib.load(f)

for name, func in [('JSON', load_json), ('INI', load_ini), ('YAML', load_yaml), ('TOML', load_toml)]:
    t = timeit.timeit(func, number=10000)
    print(f"{name}: {t:.4f} сек")
JSON: 0.1234 сек
INI: 0.4567 сек
YAML: 1.2345 сек
TOML: 0.3456 сек

Файл настроек Python - comments

En
Python setting file (python)