Python đã xuất hiện với một từ khóa mới đặc biệt vài năm trước trong Python 2. 5 được gọi là câu lệnh with. Từ khóa mới này cho phép nhà phát triển tạo trình quản lý ngữ cảnh. Nhưng đợi đã. Trình quản lý bối cảnh là gì? . Ví dụ: bạn có thể muốn mở một tệp, viết một loạt nội dung vào đó rồi đóng nó lại. Đây có lẽ là ví dụ kinh điển về trình quản lý bối cảnh. Trên thực tế, Python sẽ tự động tạo một tệp cho bạn khi bạn mở tệp bằng câu lệnh with
with open[path, 'w'] as f_obj: f_obj.write[some_data]
Quay lại Python 2. 4, bạn sẽ phải làm theo cách cũ
f_obj = open[path, 'w'] f_obj.write[some_data] f_obj.close[]
Cách thức hoạt động bí mật này là sử dụng một số phương thức kỳ diệu của Python. __enter__ và __exit__. Hãy thử tạo trình quản lý bối cảnh của riêng bạn để chứng minh cách thức hoạt động của tất cả điều này
Tạo một lớp Trình quản lý ngữ cảnh
Thay vì viết lại phương thức mở của Python ở đây, bạn sẽ tạo một trình quản lý bối cảnh có thể tạo kết nối cơ sở dữ liệu SQLite và đóng nó khi hoàn tất. Đây là một ví dụ đơn giản
import sqlite3 class DataConn: """""" def __init__[self, db_name]: """Constructor""" self.db_name = db_name def __enter__[self]: """ Open the database connection """ self.conn = sqlite3.connect[self.db_name] return self.conn def __exit__[self, exc_type, exc_val, exc_tb]: """ Close the connection """ self.conn.close[] if exc_val: raise if __name__ == '__main__': db = '/home/mdriscoll/test.db' with DataConn[db] as conn: cursor = conn.cursor[]
Trong đoạn mã trên, bạn đã tạo một lớp có đường dẫn đến tệp cơ sở dữ liệu SQLite. Phương thức __enter__ thực thi tự động tại nơi nó tạo và trả về đối tượng kết nối cơ sở dữ liệu. Bây giờ bạn đã có nó, bạn có thể tạo một con trỏ và ghi vào cơ sở dữ liệu hoặc truy vấn nó. Khi bạn thoát khỏi câu lệnh with, nó sẽ khiến phương thức __exit__ thực thi và đóng kết nối
Hãy thử tạo trình quản lý bối cảnh bằng phương pháp khác
Tạo Trình quản lý ngữ cảnh bằng contextlib
Trăn 2. 5 không chỉ thêm câu lệnh with mà còn thêm mô-đun contextlib. Điều này cho phép bạn tạo trình quản lý ngữ cảnh bằng cách sử dụng chức năng trình quản lý ngữ cảnh của contextlib làm công cụ trang trí
Rốt cuộc, hãy thử tạo một trình quản lý bối cảnh để mở và đóng một tệp
from contextlib import contextmanager @contextmanager def file_open[path]: try: f_obj = open[path, 'w'] yield f_obj except OSError: print["We had an error!"] finally: print['Closing file'] f_obj.close[] if __name__ == '__main__': with file_open['/home/mdriscoll/test.txt'] as fobj: fobj.write['Testing context managers']
Tại đây, bạn nhập trình quản lý ngữ cảnh từ contextlib và trang trí hàm file_open[] của mình với nó. Điều này cho phép bạn gọi file_open[] bằng câu lệnh with của Python. Trong hàm của bạn, bạn mở file rồi xuất ra để hàm gọi có thể sử dụng
Khi câu lệnh with kết thúc, điều khiển quay trở lại file_open[] và nó tiếp tục với mã theo sau câu lệnh năng suất. Điều đó khiến câu lệnh cuối cùng được thực thi, đóng tệp. Nếu bạn gặp lỗi OSError khi làm việc với tệp, nó sẽ bị bắt và câu lệnh cuối cùng vẫn đóng trình xử lý tệp
ngữ cảnh. đóng cửa[]
Mô-đun contextlib đi kèm với một số tiện ích tiện dụng khác. Cái đầu tiên là lớp đóng sẽ đóng thứ sau khi hoàn thành khối mã. Tài liệu Python đưa ra một ví dụ tương tự như ví dụ sau
from contextlib import contextmanager @contextmanager def closing[db]: try: yield db.conn[] finally: db.close[]
Về cơ bản, những gì bạn đang làm là tạo một hàm đóng được bao bọc trong trình quản lý bối cảnh. Điều này tương đương với những gì lớp đóng làm. Sự khác biệt là thay vì một công cụ trang trí, bạn có thể sử dụng chính lớp đóng trong câu lệnh with của mình
Đây là những gì nó sẽ trông như thế nào
from contextlib import closing from urllib.request import urlopen with closing[urlopen['//www.google.com']] as webpage: for line in webpage: # process the line pass
Trong ví dụ này, bạn mở một URL nhưng bọc nó bằng lớp đóng của bạn. Điều này sẽ khiến phần điều khiển của trang web bị đóng sau khi bạn thoát khỏi khối mã của câu lệnh with
ngữ cảnh. ngăn chặn [* ngoại lệ]
Một công cụ nhỏ tiện dụng khác là lớp triệt tiêu đã được thêm vào Python 3. 4. Ý tưởng đằng sau tiện ích quản lý bối cảnh này là nó có thể ngăn chặn bất kỳ số lượng ngoại lệ nào. Một ví dụ phổ biến là khi bạn muốn bỏ qua ngoại lệ FileNotFoundError. Nếu bạn viết trình quản lý bối cảnh sau, nó sẽ không hoạt động
>>> with open['fauxfile.txt'] as fobj: for line in fobj: print[line] Traceback [most recent call last]: Python Shell, prompt 4, line 1 builtins.FileNotFoundError: [Errno 2] No such file or directory: 'fauxfile.txt'
Trình quản lý bối cảnh này không xử lý ngoại lệ này. Nếu bạn muốn bỏ qua lỗi này thì có thể làm như sau
from contextlib import suppress with suppress[FileNotFoundError]: with open['fauxfile.txt'] as fobj: for line in fobj: print[line]
Tại đây, bạn nhập triệt tiêu và chuyển cho nó ngoại lệ mà bạn muốn bỏ qua, trong trường hợp này là ngoại lệ FileNotFoundError. Nếu bạn chạy mã này, không có gì xảy ra vì tệp không tồn tại, nhưng lỗi cũng không xuất hiện. Cần lưu ý rằng trình quản lý bối cảnh này được đăng lại. Điều này sẽ được giải thích sau trong bài viết này
ngữ cảnh. redirect_stdout / redirect_stderr
Thư viện contextlib có một vài công cụ gọn gàng để chuyển hướng thiết bị xuất chuẩn và thiết bị xuất chuẩn đã được thêm vào trong Python 3. 4 và 3. 5 tương ứng. Trước khi các công cụ này được thêm vào, nếu bạn muốn chuyển hướng thiết bị xuất chuẩn, bạn sẽ làm như thế này
Với mô-đun contextlib, giờ đây bạn có thể thực hiện các thao tác sau
from contextlib import redirect_stdout path = '/path/to/text.txt' with open[path, 'w'] as fobj: with redirect_stdout[fobj]: help[redirect_stdout]
Trong cả hai ví dụ này, bạn đang chuyển hướng thiết bị xuất chuẩn sang một tệp. Khi bạn gọi help[] của Python, thay vì in ra thiết bị xuất chuẩn, nó sẽ được lưu trực tiếp vào tệp. Bạn cũng có thể chuyển hướng thiết bị xuất chuẩn sang một số loại bộ đệm hoặc tiện ích loại điều khiển văn bản từ bộ công cụ giao diện người dùng như Tkinter hoặc wxPython
thoát khỏi ngăn xếp
ExitStack là trình quản lý bối cảnh cho phép bạn dễ dàng kết hợp các chức năng dọn dẹp và quản lý bối cảnh khác theo chương trình. Thoạt nghe có vẻ khó hiểu, vì vậy hãy xem một ví dụ từ tài liệu Python để giúp bạn hiểu ý tưởng này tốt hơn một chút
f_obj = open[path, 'w'] f_obj.write[some_data] f_obj.close[]0
Mã này về cơ bản tạo ra một loạt các trình quản lý ngữ cảnh bên trong phần hiểu danh sách. ExitStack duy trì một chồng các lệnh gọi lại đã đăng ký mà nó sẽ gọi theo thứ tự ngược lại khi đóng phiên bản, điều này xảy ra khi bạn thoát khỏi phần dưới cùng của câu lệnh with
Có rất nhiều ví dụ gọn gàng trong tài liệu Python cho contextlib nơi bạn có thể tìm hiểu về các chủ đề như sau
- Bắt ngoại lệ từ các phương thức __enter__
- Hỗ trợ một số lượng khác nhau của trình quản lý bối cảnh
- Thay thế mọi cách sử dụng try-cuối cùng
Bạn nên kiểm tra nó để bạn có cảm giác tốt về mức độ mạnh mẽ của lớp này
kết thúc
Trình quản lý bối cảnh rất thú vị và luôn có ích. Tôi luôn sử dụng chúng trong các bài kiểm tra tự động của mình để mở và đóng các hộp thoại chẳng hạn. Giờ đây, bạn sẽ có thể sử dụng một số công cụ tích hợp sẵn của Python để tạo trình quản lý bối cảnh của riêng mình. Đảm bảo dành thời gian đọc tài liệu Python trên contextlib vì có rất nhiều thông tin bổ sung không được đề cập trong chương này. Chúc bạn vui vẻ và hạnh phúc khi viết mã