Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Tiện ích cho ngữ cảnh with-statement trong Python (contextlib)


Mô-đun contextlib của thư viện chuẩn Python định nghĩa lớp ContextManager đối tượng của nó quản lý đúng cách các tài nguyên trong chương trình. Python có từ khóa with hoạt động với các context manager. Đối tượng file (được trả về bởi hàm tích hợp sẵn open()) hỗ trợ API ContextManager. Do đó chúng ta thường thấy từ khóa with được dùng khi làm việc với file.

Khối mã sau mở một file và ghi một số dữ liệu vào nó. Sau khi thao tác kết thúc, file được đóng, nếu không bộ mô tả file có thể bị rò rỉ dẫn đến hỏng file.

f = open("file.txt", "w")
f.write("hello world")
f.close()

Tuy nhiên, cùng thao tác file đó được thực hiện bằng khả năng context manager của file sử dụng cú pháp sau:

with open("file.txt", "w") as f:
    f.write("hello world")
print("file is closed")

Như đã nhắc ở trên, đối tượng file triển khai ContextManager. Nó được kích hoạt bằng từ khóa with. Khối with chứa các câu lệnh được xử lý cho đối tượng file. Ngay khi khối with kết thúc, đối tượng file tự động được đóng (phương thức close() không cần gọi tường minh). Bất kỳ đối tượng nào bị tác động bởi khối with sẽ chỉ hoạt động bên trong khối và bị loại bỏ ngay tại cuối nó.

Lớp ContextManager có hai phương thức thiết yếu __enter__() và __exit__():

__enter__() - Sẽ được gọi khi khối with bắt đầu. Nó chỉ ra rằng chương trình đã đi vào ngữ cảnh runtime liên quan đến đối tượng này.

__exit__() - Được gọi khi khối with kết thúc. Nó chỉ ra rằng chương trình thoát khỏi ngữ cảnh runtime liên quan đến đối tượng này.

Đối tượng file cũng có hai phương thức này như có thể xác nhận bằng phiên trình thông dịch sau:

>>> f = open("file.txt", "w")
>>> f.__enter__()
<_io.TextIOWrapper name='file.txt' mode='w' encoding='cp1252'>
>>> f.write("hello world")
11
>>> f.__exit__()
>>> f.write("hello world")
Traceback (most recent call last):
  File "<pyshell#10>", line 1, in <module>
    f.write("hello world")
ValueError: I/O operation on closed file.

Khi phương thức __exit__() được gọi, file bị đóng. Đó là lý do ValueError xuất hiện khi chúng ta cố ghi dữ liệu vào file sau khi nó đã đóng.

Dưới đây là một cách dùng tổng quát hơn của contextManager. Trước tiên chúng ta định nghĩa một lớp với phương thức __enter__() và __exit__() và kích hoạt contextManager cho đối tượng của nó bằng câu lệnh with.

import contextlib
class WithExample:
    def __init__(self):
        print("object initialized")
    def __enter__(self):
        print("entered context")
    def __exit__(self, *args):
        print("exited context")
with WithExample() as w:
    print('this is a contextlib example')
    print('used by with statement')
    print('end of with block')

Đầu ra cho thấy ngay khi khối with bắt đầu, phương thức __enter__() được thực thi. Các câu lệnh trong khối được xử lý. Khi khối kết thúc, phương thức __exit__() cũng được tự động gọi.

object initialized
entered context
this is a contextlib example
used by with statement
exited context
end of with block

Mô-đun contextlib có trình trang trí @contextmanager nhờ đó chúng ta có thể viết một hàm factory dựa trên generator để tự động hỗ trợ câu lệnh with. Quản lý ngữ cảnh của đối tượng file với trình trang trí như sau:

from contextlib import contextmanager
@contextmanager
def openfile(name):
    try:
        f = open(name, 'w')
        yield f
    finally:
        f.close()
with openfile('file.txt') as f:
    f.write('hello world')
print('file is closed')

ContextManager do đó là một tính năng rất hữu ích của Python để quản lý hiệu quả tài nguyên trong chương trình.