2012-01-03 31 views
7

Trong this question, tôi đã xác định trình quản lý ngữ cảnh chứa trình quản lý ngữ cảnh. Cách chính xác nhất để thực hiện việc lồng ghép này là gì? Tôi đã gọi số self.temporary_file.__enter__() trong số self.__enter__(). Tuy nhiên, trong self.__exit__, tôi khá chắc chắn tôi phải gọi self.temporary_file.__exit__(type_, value, traceback) trong một khối cuối cùng trong trường hợp ngoại lệ được nêu ra. Tôi có nên đặt thông số type_, value và traceback nếu có sự cố trong số self.__exit__ không? Tôi đã kiểm tra contextlib nhưng không thể tìm thấy bất kỳ tiện ích nào để trợ giúp việc này.Quản lý ngữ cảnh lồng nhau của Python

đang gốc từ câu hỏi:

import itertools as it 
import tempfile 

class WriteOnChangeFile: 
    def __init__(self, filename): 
     self.filename = filename 

    def __enter__(self): 
     self.temporary_file = tempfile.TemporaryFile('r+') 
     self.f = self.temporary_file.__enter__() 
     return self.f 

    def __exit__(self, type_, value, traceback): 
     try: 
      try: 
       with open(self.filename, 'r') as real_f: 
        self.f.seek(0) 
        overwrite = any(
         l != real_l 
         for l, real_l in it.zip_longest(self.f, real_f)) 
      except IOError: 
       overwrite = True 
      if overwrite: 
       with open(self.filename, 'w') as real_f: 
        self.f.seek(0) 
        for l in self.f: 
         real_f.write(l) 
     finally: 
      self.temporary_file.__exit__(type_, value, traceback) 

Trả lời

9

Cách đơn giản để tạo ra các nhà quản lý bối cảnh là với contextlib.contextmanager. Một cái gì đó như thế này:

@contextlib.contextmanager 
def write_on_change_file(filename): 
    with tempfile.TemporaryFile('r+') as temporary_file: 
     yield temporary_file 
     try: 
      ... some saving logic that you had in __exit__ ... 

Sau đó, sử dụng with write_on_change_file(...) as f:.
Phần thân của câu lệnh with sẽ được thực thi “thay vì” số yield. Tự quấn yield vào khối try nếu bạn muốn bắt bất kỳ ngoại lệ nào xảy ra trong cơ thể.

Tệp tạm thời sẽ luôn được đóng đúng cách (khi các khối with kết thúc).

+0

Điều này thật sự rất hay. Tôi sẽ để câu hỏi mở một chút trong trường hợp câu hỏi này tạo ra bất kỳ câu trả lời hay nào khác. –

+3

Sử dụng '@ contextlib.contextmanager' rất thuận tiện, nhưng vẫn có những trường hợp thích hợp để sử dụng một lớp với các phương thức' __enter__' và '__exit__' được định nghĩa theo cách thủ công. Bạn có lời khuyên nào về việc đó không? – Zearin

+0

Vâng, hãy làm điều đó khi nó thuận tiện hơn - ví dụ khi đối tượng cần làm nhiều hơn chỉ là một trình quản lý ngữ cảnh (mặc dù trong trường hợp đó bạn cũng nên xem xét thêm một phương thức @ contextlib.contextmanager). –

Các vấn đề liên quan