Комментарии 11
Это что-то типа RAII в С++.
Что-то вроде того. Только куда больше простор для использования. Едва ли не для всего что может быть представлено в виде поготовка-действие-завершение
Жаль, что в статье не рассмотрено применение в юнит тестах - удобно всякую фигню мокать на ходу.
Ещё в питоне можно вызвать несколько контекстов одновременно - через вложенные with или вот так
with A() as X, B() as Y, C() as Z:
Вопрос со звёзочкой: в сколько контекстов можно зайти одновременно? :D
Я чуть мозг не сломал с последним примером.
old_mask = None
, потом old_mask = umask(mask)
, а финалка umask(old_mask)
. Наивно получается, что устанавливается новая маска, хотя вокруг написано про "временно".
Я знаю umask, но я не знаю как именно работает umask, ну не было у меня опыта поработать плотно.
Полез в код:
https://github.com/certbot/certbot/blob/master/certbot/certbot/compat/filesystem.py#L64
Добавь плиз для контекста, что ОНО возвращает предыдущую маску
def umask(mask: int) -> int:
"""
Set the current numeric umask and return the previous umask. On Linux, the built-in umask
method is used. On Windows, our Certbot-side implementation is used.
:param int mask: The user file-creation mode mask to apply.
:rtype: int
:return: The previous umask value.
"""
if POSIX_MODE:
return os.umask(mask)
previous_umask = _WINDOWS_UMASK.mask
_WINDOWS_UMASK.mask = mask
return previous_umask
Контекст менеджеры в питоне это компромисс между читабельностью и явностью (в смысле explicit is better than implicit). Используя контекст менеджер нужно постоянно держать в голове его особенности: Single Use, Reusable or Reentrant, помноженные на потокобезопасность и возможность использовать с async - пользовательский код будет выглядеть абсолютно одинаково, а поведение существенно разным.
Например:
# Где-то в другом файле
…
with filesystem.temp_umask(mask):
util.set_up_core_dir(...)
Как поведет себя этот код будучи вызванным одновременно в разных потоках с разными значениями mask?
Ох мне недавно понадобилось сделать что то подобное, голову сломал.
Если на примерах покажете то же создание и завершение сессии в БД, либо к стороннему API, в рамках синхронного/асинхронного подхода. Я думаю сообществу это бы понадобилось.
Обычно в документации к коннекторам это есть.
Если какое-то API требует действия после работы, но не имеет контекстного менеджера, я взял себе за правило делать его самостоятельно, благо это очень легко.
Асинхронные контекстные менеджеры тоже есть, но я с ними не работал, но в общем идея та же, только внутри можно await использовать.
В Python множество инструментов, которые могут помочь улучшить читаемость кода, и Context manager, о котором дальше пойдет речь, один из них.
Не уверен, что контекстный менеджеры для читаемости, это больше инструмент позволяющий два завязанных по времени выполнения действий, выполнить в заданном порядке и с гарантией вызова обоих действий. Такой подход избавляет от возможных человеческих ошибок. По моему опыту почти все, кто открывают файл руками, не закрывают его правильно.
Context manager в рамках языка Python