Hai cách: viết class có __enter__/__exit__, hoặc dùng @contextlib.contextmanager với một generator yield đúng một lần.
python
import contextlib
import time
@contextlib.contextmanager
def timed(label):
start = time.perf_counter()
try:
yield # body of the with-block runs here
finally:
print(label, time.perf_counter() - start)
with timed("query"):
run_query()Phần dọn dẹp phải nằm trong finally, nếu không thì block có exception sẽ không dọn.
__exit__ trả về True: exception bị nuốt hoàn toàn — chương trình chạy tiếp ngay sau khối with như chưa có gì xảy ra. Trả về None/False (mặc định) thì exception tiếp tục lan ra.
python
class Suppress:
def __enter__(self): return self
def __exit__(self, exc_type, exc, tb):
return exc_type is ValueError # only ValueError is swallowedVới @contextmanager, tương đương là bắt exception quanh yield mà không raise lại.
- Nếu chỉ muốn log rồi cho lỗi đi tiếp thì bắt buộc
raiselại. - Chỉ nuốt exception khi thật sự có chủ đích — muốn bỏ qua có kiểm soát thì đã có sẵn
contextlib.suppress.