Trong Python, trình quản lý bối cảnh là một đối tượng có thể được sử dụng trong câu lệnh with Timer("doing stuff"): for i in range(1000000): pass2. Đây là trình quản lý ngữ cảnh báo cáo tổng thời gian đồng hồ treo tường đã sử dụng bên trong khối with Timer("doing stuff"): for i in range(1000000): pass2
import time class Timer(object): def __init__(self, msg): self._msg = msg def __enter__(self): # time.monotonic() requires Python >= 3.3 self._start = time.monotonic() def __exit__(self, exc_type, exc_value, exc_traceback): if exc_type: print('Failed: {}: {}'.format(self._msg, exc_value)) else: print('{}: {} s'.format(self._msg, time.monotonic() - self._start))
Chúng ta có thể sử dụng nó như thế này
with Timer("doing stuff"): for i in range(1000000): pass
cái nào tạo ra đầu ra này
doing stuff: 0.04281306266784668 sXử lý ngoại lệ
Trình quản lý ngữ cảnh cũng có thể xử lý các ngoại lệ từ bên trong khối mà chúng bảo vệ. with Timer("doing stuff"): for i in range(1000000): pass4 làm điều này. Nếu chúng ta làm
with Timer("doing stuff"): raise ValueError('ack')
chúng tôi nhận được
Failed: doing stuff: ack Traceback (most recent call last): File "test.py", line 20, in <module> raise ValueError('ack') ValueError: ackBởi vì with Timer("doing stuff"): for i in range(1000000): pass5 không trả lại with Timer("doing stuff"): for i in range(1000000): pass6, ngoại lệ tiếp tục lan truyền, vì vậy chúng tôi thấy cả thông báo with Timer("doing stuff"): for i in range(1000000): pass7 và truy nguyên. Nếu with Timer("doing stuff"): for i in range(1000000): pass5 trả về with Timer("doing stuff"): for i in range(1000000): pass6, ngoại lệ sẽ bị trình quản lý bối cảnh nuốt và chúng tôi sẽ chỉ thấy dòng with Timer("doing stuff"): for i in range(1000000): pass7
Bối cảnh từ trình quản lý bối cảnh
Giả sử chúng ta muốn trình quản lý bối cảnh trả về một số thông tin, có lẽ là mức độ chi tiết của bộ đếm thời gian. Chúng ta có thể sửa đổi doing stuff: 0.04281306266784668 s 1 như thế này
def __enter__(self): # time functions require Python >= 3.3 self._start = time.monotonic() return time.clock_getres(time.CLOCK_MONOTONIC)
Bây giờ chúng ta có thể làm
with Timer("doing stuff") as resolution: print('Resolution: {}'.format(resolution)) for i in range(1000000): pass
sản xuất
Resolution: 1e-09 doing stuff: 0.043778783998277504 sNgười trang trí doing stuff: 0.04281306266784668 s 2
Viết trình quản lý bối cảnh liên quan đến một số bản soạn sẵn. các phương thức doing stuff: 0.04281306266784668 s 1 và with Timer("doing stuff"): for i in range(1000000): pass5 và có thể là một phương thức doing stuff: 0.04281306266784668 s 5 để xử lý bất kỳ đối số nào. Có một cách dễ dàng hơn. người trang trí doing stuff: 0.04281306266784668 s 6. Chúng ta có thể viết lại with Timer("doing stuff"): for i in range(1000000): pass4 như thế này
import contextlib import time @contextlib.contextmanager def Timer(msg): start = time.monotonic() try: yield time.clock_getres(time.CLOCK_MONOTONIC) except BaseException as e: print('Failed: {}: {}'.format(msg, e)) raise else: print('{}: {} s'.format(msg, time.monotonic() - start))
Bây giờ with Timer("doing stuff"): for i in range(1000000): pass4 chỉ là một trình tạo ra kết quả một lần (mang lại giá trị bị ràng buộc bởi câu lệnh with Timer("doing stuff"): for i in range(1000000): pass2). Biểu thức with Timer("doing stuff"): raise ValueError('ack')0 đưa ra bất kỳ ngoại lệ nào được ném ra khỏi khối, sau đó trình quản lý ngữ cảnh có thể xử lý hay không
tự quản lý
Một cách sử dụng cho trình quản lý bối cảnh là đảm bảo rằng một đối tượng (tệp, kết nối mạng, xử lý cơ sở dữ liệu) được đóng khi rời khỏi một khối. with Timer("doing stuff"): raise ValueError('ack')1 làm điều này. phương thức with Timer("doing stuff"): for i in range(1000000): pass5 của nó gọi một đối tượng khác là with Timer("doing stuff"): raise ValueError('ack')3. Sử dụng nó như thế này
import contextlib with contextlib.closing(open("/etc/passwd")) as fh: lines = fh.readlines()
Nhưng điều đó có vẻ hơi dài dòng. Một cách tiếp cận tốt hơn. nhiều đối tượng triển khai doing stuff: 0.04281306266784668 s 1 và with Timer("doing stuff"): for i in range(1000000): pass5, vì vậy bạn có thể sử dụng chúng để tự quản lý. Việc triển khai with Timer("doing stuff"): raise ValueError('ack')6 (loại được trả về bởi with Timer("doing stuff"): raise ValueError('ack')7) có nội dung như thế này