Chuyển đến nội dung chính
Mô-đun 9 · Bài học 3 trong tổng số 435/36 trong khóa học~12 min
Bài học theo mô-đun (3/4)

Trình quản lý bối cảnh: với và __enter__/__exit__

trình quản lý ngữ cảnh là đối tượng bạn sử dụng với with. Nó đảm bảo rằng một số thao tác thiết lập/dọn dẹp nhất định luôn diễn ra, ngay cả khi xảy ra lỗi. Ví dụ chuẩn: mở và đóng một tập tin.

Mẫu with

Python
with open("note.txt", "w") as f:
    f.write("ciao")
# qui f è già chiuso, anche se write() ha sollevato un'eccezione

Bằng tiếng Anh đơn giản: "với tài nguyên X mở dưới dạng f, hãy làm điều này. Khi hoàn tất (bất kể điều gì xảy ra), hãy đóng X." Nếu không có with bạn sẽ phải viết try/finally mỗi lần.

Nhiều hơn một cùng một lúc

Python
with open("a.txt") as f, open("b.txt") as g:
    dati_a = f.read()
    dati_b = g.read()

Viết trình quản lý bối cảnh của riêng bạn (lớp)

Bạn cần xác định hai phương pháp giải mã: __enter__ và __exit__.

Python
class Timer:
    def __enter__(self):
        import time
        self.t0 = time.perf_counter()
        return self  # è l'oggetto che finisce dopo "as"
    def __exit__(self, exc_type, exc_value, traceback):
        import time
        self.elapsed = time.perf_counter() - self.t0
        # ritornare True ingoia l'eccezione; di solito non lo vuoi
        return False

with Timer() as t:
    sum(range(10**6))
t.elapsed  # quanto è durato
  • __enter__(self) được gọi khi vào khối; giá trị trả về là giá trị bạn nhận được sau as.
  • __exit__(self, exc_type, exc_value, tb) được gọi khi thoát (luôn luôn). Nếu nó trả về True thì mọi ngoại lệ đều bị loại bỏ.

Phím tắt: @contextmanager

contextlib.contextmanager cho phép bạn viết trình quản lý bối cảnh dưới dạng chức năng tạo:

Python
from contextlib import contextmanager

@contextmanager
def timer():
    import time
    t0 = time.perf_counter()
    try:
        yield  # qui sta il blocco "with"
    finally:
        elapsed = time.perf_counter() - t0
        print(f"durata: {elapsed:.4f}s")

with timer():
    sum(range(10**6))

Mã trước yield là __enter__, mã sau là __exit__. try/finally đảm bảo dọn dẹp ngay cả khi xảy ra lỗi.

ngăn chặn: bỏ qua một ngoại lệ

Python
from contextlib import suppress

with suppress(FileNotFoundError):
    open("forse-non-esiste.txt").read()
# se il file non c'è, nessun errore propaga

Cạm bẫy: with chỉ dành cho những đối tượng hỗ trợ nó

Python
x = 42
with x:  # AttributeError: __enter__
    ...

Viết trình quản lý bối cảnh với @contextmanager

Mô-đun contextlib của thư viện chuẩn xuất một trình trang trí rất tiện lợi có tên @contextmanager để tạo trình quản lý bối cảnh bằng cách sử dụng các hàm tạo, thay vì viết các lớp dài dòng triển khai các phương thức __enter__ và __exit__. Bạn chỉ cần viết một hàm tạo sử dụng một yield duy nhất:

Python
from contextlib import contextmanager

@contextmanager
def manage_resource():
    # __enter__ code
    yield resource
    # __exit__ code

Hãy tự mình thử

tập thể dục#python.m9.l3.e1
Nỗ lực: 0Đang tải…

Sử dụng contextlib.suppress để thử int('non-numero') bỏ qua ValueError. Sau khối gán `ok = True`. Đánh giá `được`.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

ngăn chặn (ValueError) chỉ nuốt ValueError.

Giải pháp khả dụng sau 3 lần thử

Xem lại bài tập

tập thể dục#python.m9.l3.e2
Nỗ lực: 0Đang tải…

Viết trình quản lý bối cảnh `collect` với @contextmanager để tạo ra một danh sách trống và khi thoát, chuyển đổi nó thành một bộ dữ liệu (in nó). Sử dụng nó để nối 1, 2, 3 vào danh sách bên trong khối. Cuối cùng, hãy đánh giá `len(bộ sưu tập)` trong đó `bộ sưu tập` là danh sách thu được.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

mang lại các mục để hiển thị danh sách bên trong khối with.

Giải pháp khả dụng sau 3 lần thử

Thử thách bổ sung

tập thể dục#python.m9.l3.e3
Nỗ lực: 0Đang tải…

Write a custom context manager using the `@contextmanager` decorator from `contextlib`. The context manager must be named `mock_session`. Upon entry, it must append `'start'` to a global list `log_list = []`, yield control using `yield`, and upon exit append `'stop'`. Finally, evaluate `log_list` after using the context manager with `with mock_session():`.

Đang tải trình chỉnh sửa…
Hiển thị gợi ý

Sử dụng năng suất bên trong mock_session để tạm dừng thực thi trước khi thêm 'stop'.

Giải pháp khả dụng sau 3 lần thử