2013-10-16 8 views
14

नोट: मैंखोलें संदर्भ प्रबंधक के रूप में

with open('f1') as f1, open('f2') as f2: 
    ... 

वाक्य रचना के बारे में पता कर रहा हूँ। यह एक अलग सवाल है।


तार file_names की एक सूची को देखते हुए वहाँ एक लाइन का उपयोग कर कि में हर फ़ाइल नाम को खोलने के लिए with/as का उपयोग कर एक तरीका है। कुछ ऐसा:

with [open(fn) for fn in file_names] as files: 
    # use the list of files 

जो निश्चित रूप से काम नहीं करता है क्योंकि यह किसी सूची में संदर्भ प्रबंधक का उपयोग करने का प्रयास करता है। सूची की लंबाई रन-टाइम तक ज्ञात नहीं हो सकती है, जैसे कि sys.argv[1:]

+0

आप अपना खुद का संदर्भ प्रबंधक लिख सकते हैं। क्या यह एक विकल्प है? यह बहुत आसान है। http://docs.python.org/release/2.5.1/ref/context-managers.html –

उत्तर

9

आप अजगर 3.3+ के लिए उपयोग किया है, वहाँ एक विशेष वर्ग इस उद्देश्य के लिए वास्तव में तैयार किया गया है: अजगर 3.x पर हैं, यहां अजगर 2.7 स्रोत से कोड है। यह वैसे ही काम करता है जैसे आप उम्मीद करेंगे:

with contextlib.ExitStack() as stack: 
    files = [stack.enter_context(open(fname)) for fname in filenames] 
    # All opened files will automatically be closed at the end of 
    # the with statement, even if attempts to open files later 
    # in the list raise an exception 
7

इसके बारे में कैसे?

class ListContext: 
    def __init__(self, l): 
     self.l = l 

    def __enter__(self): 
     for x in self.l: 
      x.__enter__() 
     return self.l 

    def __exit__(self, type, value, traceback): 
     for x in self.l: 
      x.__exit__(type, value, traceback) 

arr = ['a', 'b', 'c'] 

with ListContext([open(fn, 'w') for fn in arr]) as files: 
    print files 

print files 

आउटपुट है:

[<open file 'a', mode 'w' at 0x7f43d655e390>, <open file 'b', mode 'w' at 0x7f43d655e420>, <open file 'c', mode 'w' at 0x7f43d655e4b0>] 
[<closed file 'a', mode 'w' at 0x7f43d655e390>, <closed file 'b', mode 'w' at 0x7f43d655e420>, <closed file 'c', mode 'w' at 0x7f43d655e4b0>] 

सूचना, वे संदर्भ के साथ अंदर खुले हैं और बाहर बंद कर दिया।

यह पायथन context manager API का उपयोग कर रहा है।

संपादित करें: ऐसा लगता है यह पहले से ही मौजूद है, लेकिन पदावनत है जैसे: contextlib और this SO question देखें। इस तरह यह प्रयोग करें:

import contextlib 

with contextlib.nested(*[open(fn, 'w') for fn in arr]) as files: 
    print files 
print files 
+0

'contextlib.nested' को –

+0

बहिष्कृत किया गया है, धन्यवाद। यहां दिए गए 'ListContext' में एक ही चेतावनी है .. यानी समस्याएं होती हैं यदि आंतरिक तत्वों के '__enter __()' या '__exit __()' अपवाद ट्रिगर अपवाद होते हैं। – Max

1

ऐसा लगता है कि आप मूल रूप से contextlib.nested() लिए देख रहे हैं की तरह, इस अजगर 2.7 में with बयान के कई प्रबंधक प्रपत्र के पक्ष में पदावनत किया गया था लेकिन डॉक्स में बताया गया है:

बयान के साथ की कई प्रबंधक प्रपत्र पर इस समारोह में से एक लाभ यह है कि तर्क unpacking यह संदर्भ प्रबंधकों

के परिवर्तनशील साथ प्रयोग किया जा करने के लिए मामले में अनुमति देता है आप ExitStack:

from contextlib import contextmanager 

@contextmanager 
def nested(*managers): 
    """Combine multiple context managers into a single nested context manager.                            
    This function has been deprecated in favour of the multiple manager form 
    of the with statement. 

    The one advantage of this function over the multiple manager form of the 
    with statement is that argument unpacking allows it to be 
    used with a variable number of context managers as follows: 

     with nested(*managers): 
      do_something() 

    """ 
    warn("With-statements now directly support multiple context managers", 
     DeprecationWarning, 3)                                         exits = [] 
    vars = [] 
    exc = (None, None, None) 
    try: 
     for mgr in managers: 
      exit = mgr.__exit__ 
      enter = mgr.__enter__ 
      vars.append(enter()) 
      exits.append(exit) 
     yield vars 
    except: 
     exc = sys.exc_info() 
    finally: 
     while exits: 
      exit = exits.pop() 
      try: 
       if exit(*exc): 
        exc = (None, None, None) 
      except: 
       exc = sys.exc_info() 
     if exc != (None, None, None): 
      # Don't rely on sys.exc_info() still containing 
      # the right information. Another exception may 
      # have been raised and caught by an exit method 
      raise exc[0], exc[1], exc[2] 
संबंधित मुद्दे