2012-01-03 15 views
7

this question में, मैंने एक संदर्भ प्रबंधक को परिभाषित किया जिसमें संदर्भ प्रबंधक शामिल है। इस घोंसले को पूरा करने का सबसे आसान तरीका क्या है? मैंने को self.__enter__() पर कॉल करना समाप्त कर दिया। हालांकि, self.__exit__ में, मुझे पूरा यकीन है कि मुझे अपवाद उठाए जाने पर अंत में ब्लॉक में self.temporary_file.__exit__(type_, value, traceback) पर कॉल करना होगा। क्या मुझे self.__exit__ में कुछ गलत होने पर टाइप_, मान और ट्रेसबैक पैरामीटर सेट करना चाहिए? मैंने contextlib की जांच की, लेकिन इसके साथ मदद करने के लिए कोई उपयोगिता नहीं मिली।नेस्टिंग पायथन संदर्भ प्रबंधक

सवाल से मूल कोड:

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) 

उत्तर

9

आसान तरीका संदर्भ प्रबंधकों बनाने के लिए contextlib.contextmanager के साथ है। कुछ इस तरह:

@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__ ... 

फिर with write_on_change_file(...) as f: का उपयोग करें।
with कथन का शरीर yield "के बजाय" निष्पादित किया जाएगा। yield को try ब्लॉक में लपेटें यदि आप शरीर में होने वाले किसी भी अपवाद को पकड़ना चाहते हैं।

अस्थायी फ़ाइल हमेशा ठीक से बंद हो जाएगी (जब इसकी with ब्लॉक समाप्त होती है)।

+0

यह वास्तव में अच्छा है। यदि कोई प्रश्न किसी अन्य अच्छे उत्तर उत्पन्न करता है तो मैं थोड़ी देर के लिए प्रश्न खोलने जा रहा हूं। –

+3

'contextlib.contextmanager' का उपयोग करना सुविधाजनक है, लेकिन अभी भी ऐसे मामले हैं जहां मैन्युअल रूप से परिभाषित '__enter__' और' __exit__' विधियों के साथ कक्षा का उपयोग करना उचित है। क्या आपको ऐसा करने पर कोई सलाह है? – Zearin

+0

ठीक है, यह अधिक सुविधाजनक होने पर करें - उदाहरण के लिए जब ऑब्जेक्ट को केवल संदर्भ प्रबंधक होने से अधिक करने की आवश्यकता होती है (हालांकि उस स्थिति में आपको @ contextlib.contextmanager विधि जोड़ने पर भी विचार करना चाहिए)। –

संबंधित मुद्दे