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