В Golang defer
, которая планирует отложенное действие при выходе из текущей функции. Часто этим пользуются как контекстным менеджером, типа, открываешь файл и тут же при помощи defer
планируешь его закрытие:
f := createFile("/tmp/defer.txt")Причём закрытие файла выполнится даже если где-то дальше в этой функции произойдёт ошибка — это предотвращает утечку ресурсов. Ещё при помощи
defer closeFile(f)
defer
можно, собственно, перехватывать и обрабатывать разные ошибки. Короче, да, примерно как контекстные менеджеры или блоки try-finally
, но не создают дополнительный уровень вложенности в коде, а ещё открытие и закрытие ресурса обычно находятся в коде рядом друг с другом, а не на разных концах файла. Можно выполнить несколько defer
— они складываются в стэк, а при завершении функции по очереди снимаются со стэка и выполняются (получается, в обратном порядке).К чему я это. Чувак с реддита сделал аналог такой инструкции для питона. Работает следующим образом:
@defersВызов
def f():
print(1)
defer: print(3)
print(2)
f()
напечатает 1 2 3
. Почти как на Go, только с декоратором над функцией и лишним двоеточием после defer
.Под капотом там происходит разбор и модификация AST тела функции, задекорированной
@defers. Обратите внимание на строчку
defer: print(3). Синтаксически здесь происходит аннотация переменной
defer
, а в тайп-хинте лежит какой-то вызов функции. Python игнорирует тайп-хинты для переменных в теле функций, то есть функцию вызывать он не будет даже пытаться — можно положить туда что угодно, лишь бы соответствовало синтаксису. Библиотека выполняет код из тайп-хинта на выходе из функции. Интересная эксплуатация особенностей языка!Автор не рекомендует пользоваться этим в продакшене. Это скорее забавная поделка, чем рабочий инструмент. Но если всё-таки будете, то обязательно применять в комплекте с:
result, err = do_thing()Иначе не прочувствуете вайб!
if err is not None:
return None, err
GitHub | Тред на реддите