Các chi tiết được một chút kỹ thuật, vì vậy chúng ta hãy bắt đầu với phiên bản đơn giản:
Một số loại biết làm thế nào để được sử dụng trong một tuyên bố with
. Đối tượng tệp, giống như những gì bạn nhận được từ open
, là ví dụ về loại như vậy. Khi nó quay ra, các đối tượng mà bạn lấy lại từ urllib.request.urlopen
, là cũng là ví dụ về loại đó, vì vậy ví dụ thứ hai của bạn có thể được viết giống như cách đầu tiên.
Nhưng một số loại không biết cách sử dụng trong tuyên bố with
.Chức năng closing
được thiết kế để bọc các loại đó - miễn là chúng có phương thức close
, nó sẽ gọi phương thức close
của chúng tôi khi bạn thoát khỏi câu lệnh with
.
Tất nhiên một số loại không biết cách sử dụng trong tuyên bố with
và cũng không thể sử dụng với closing
vì phương pháp dọn dẹp của chúng không được đặt tên là close
(hoặc vì làm sạch chúng phức tạp hơn đóng chúng). Trong trường hợp đó, bạn cần phải viết một trình quản lý ngữ cảnh tùy chỉnh. Nhưng ngay cả điều đó cũng không quá khó.
Về kỹ thuật:
Một tuyên bố with
đòi hỏi một context manager, một đối tượng với __enter__
và __exit__
phương pháp. Nó sẽ gọi phương thức __enter__
và cung cấp cho bạn giá trị trả về theo phương thức đó trong mệnh đề as
và sau đó nó sẽ gọi phương thức __exit__
ở cuối câu lệnh with
.
Đối tượng tệp được kế thừa từ io.IOBase
, là trình quản lý ngữ cảnh có phương thức __enter__
tự trả về và có __exit__
cuộc gọi self.close()
.
Đối tượng được trả về bởi urlopen
là (giả sử một http
hoặc https
URL) một HTTPResponse
, trong đó, như các tài liệu nói, "có thể được sử dụng với một tuyên bố with
".
Các closing
chức năng:
Return một người quản lý bối cảnh đó đóng cửa điều sau khi hoàn thành khối. Đây là về cơ bản tương đương với:
@contextmanager
def closing(thing):
try:
yield thing
finally:
thing.close()
Nó không phải luôn luôn 100% rõ ràng trong các tài liệu mà loại là các nhà quản lý bối cảnh và những loại thì không. Đặc biệt vì đã có một ổ đĩa lớn kể từ 3.1 để làm mọi thứ có thể là một trình quản lý ngữ cảnh thành một (và, cho vấn đề đó, để làm mọi thứ giống như tập tin thành IOBase
thực tế), nhưng nó vẫn không 100% hoàn thành là 3,4.
Bạn luôn có thể dùng thử và xem. Nếu bạn nhận được AttributeError: __exit__
, thì đối tượng không thể sử dụng làm người quản lý ngữ cảnh. Nếu bạn nghĩ rằng nó nên được, nộp một lỗi cho thấy sự thay đổi. Nếu bạn không gặp lỗi đó, nhưng các tài liệu không đề cập đến nó là hợp pháp, hãy gửi một lỗi đề xuất tài liệu được cập nhật.
Tôi sắp đề nghị ai đó nên gửi một lỗi tài liệu trên 'contextlib' cho điều này, và nếu đó không phải là bạn nên tin bạn ... nhưng trước khi tôi có thể kết thúc, Martijn đã đệ trình lỗi, với liên kết quay lại đây. :) – abarnert