Post content
Недавно была задача форматировать строки по шаблону. Шаблон обычный для метода format() /path/to/app{version}/bin или /opt/{app_name}/bin:{DEFAULT_PATH}:/usr/bin Проблема состояла в том, что некоторые переменные следует игнорировать, заменять только те, что у меня есть на данный момент (дальше идет ещё один обработчик). Если в метод строки format() не передать все переменные то будет ошибка KeyError "/opt/{app_name}:{DEFAULT_PATH}".format(app_name="my_app") # KeyError: 'DEFAULT_PATH' Какие варианты решения есть? ▫️ переопределить класс srt и метод format ▫️ написать отдельную функцию парсинга строки с использованием regex ▫️ сделать словарь, который возвращает исходную переменную при отсутствии ключа Третий вариант и рассмотрим, он самый краткий, буквально 2 строки включая вызов! class SkipDict(dict): def __missing__(self, key): return f"{{{key}}}" "/opt/{app_name}:{DEFAULT_PATH}".format_map(SkipDict(app_name='my_app')) # "/opt/my_app:{DEFAULT_PATH}" 1. Мы создаем кастомный класс наследуя его от dict и переопределяем __missing__. Этот метод вызывается когда в словаре ключ не найден. По умолчанию он выбрасывает исключение KeyError. Всякий раз когда ключ не найден, мы возвращаем исходный вид этой переменной и ошибки теперь не будет. 2. Это не сработает если переменные указаны в формате ${name}. Это совсем другой синтаксис из bash и подобных сред. 3. Переменные можно передать и просто готовым словарём. Это же обычный конструктор объекта dict "...".format_map(SkipDict(kwargs)) 4. Вместо format() используется format_map(), просто удобней в данном случае. 5. Ну да, не две строки. Просто класс нужно создать и в одну строку. Если кому надо именно 2х-строчное решение - забирайте: SkipDict = type('SkipDict', (dict, ),{'__missing__': lambda self, key: f"{{{key}}}"}) 6. Из минусов: вы не сможете так просто определить все ли вам нужные переменные заполнены, так как пропускаются ВСЕ отсутствующие. #tricks