Комментарии 9
Сюда можно добавить про библиотеку contextlib
с декоратором contextmanager
.
Нет необходимости писать класс для нового контекстного менеджера, достаточно обернуть генератор в декоратор @contextmanager
. Ссылка на доку: contextlib — Utilities for with-statement contexts
Пример из документации:
from contextlib import contextmanager
@contextmanager
def managed_resource(*args, **kwds):
# Code to acquire resource, e.g.:
resource = acquire_resource(*args, **kwds)
try:
yield resource
finally:
# Code to release resource, e.g.:
release_resource(resource)
Использование:
with managed_resource(timeout=3600) as resource:
# Resource is released at the end of this block,
# even if code in the block raises an exception
Там много ещё чего.
class AsyncTimer:
def __enter__(self):
async def __aexit__(self, exc_type, exc_val, exc_tb):
С такой комбинацией дандеров это в принципе не контекст менеджер.
В парсерах часто использую где нужно подтягивать селениум. Штука тяжелая, потому от лишних экземпляров стоит сразу избавляться.
А вы не могли бы более подробно объяснить, что делает вот этот код?
with threading.Lock() as lock:
# Блокировка ресурса перед выполнением задачи
lock.acquire()
try:
t = threading.Thread(target=worker)
t.start()
finally:
# Освобождение ресурса после выполнения задачи
lock.release()
Он не работает.
lock в данном случае содержит результат блокировки, а сам лок
Если бы там был все таки Лок, мы бы получили двойную блокировку (одна из-за контекстного менеджера, вторая из-за aquire)
Если бы мы взяли RLock вместо Lock, это позволило бы внутри одного контекста повторно вызвать aquire, но код бы все равно не имел смысла, потому что Лок используется только в одном потоке
Метод для предоставления асинхронного контекста называется __aenter__
P.s.: порой кажется, что статьи здесь пишутся абы как, так ещё и редакторы их вообще не смотрят
Как-то очень вскользь сказано про обработку исключений. Хотя это, в сущности, первое, для чего были изначально предназначены контекстные менеджеры - удобная обертка над try ... finally
.
Суть контекстного менеджера в том, что в констукции with
гарантируется, что если метод __enter__()
был выполнен без ошибок, то метод __exit__()
будет вызван всегда. Закрытие файлов, соединений и т. п. финализирующие операции - это только примеры того, что может потребоваться сделать при выходе контекста. А выходим мы из контекста либо после выполнения всех операци в блоке with
. Тогда в качестве параметров в метод __exit__
передаетя три значения None
. Либо если в блоке with
возникает необработанное исключение. Тогда в __exit__
попадает информмация об этом исключении в виде 3 параметров, которые представляют собой ничто иное как кортеж значений, возвращаемых функцией sys.exc_info(), будучи вызванной внутри блока finally
.
Внутри __exit__
исключение можно обработать или передать выше. Если __exit__
возвращает любое истинное значение, тогда исключение считается обработанным, и выполнение кода продолжается с места выхода из контекстного менеджера. Если __exit__
возвращает ложное значение, например None
, то при выходе из метода исключение будет обрабатываться обычным образом. При этом стоит помнить, что новые исключения, возникшие в ходе выполнения метода __exit__
, всегда замещают исключения, которые могли возникнуть в ходе выполнения тела with
и попали в параметры метода __exit__
.
Менеджер контекста это просто