2013-10-16 72 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

如果你有機會到Python 3.3+,有一類特殊的正是爲此而設計的:在ExitStack。它的工作方式與您所期望的相同:

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>] 

通告,它們與上下文內的打開和關閉外部。

這是使用Python的context manager API

編輯:它似乎已經存在,但是已棄用:請參閱contextlibthis 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(),這個被廢棄在Python 2.7贊成with語句的多個經理形式,但作爲文檔指出:

此功能在的with語句中的多個經理形式的一個優點是這樣的說法拆包允許它與上下文管理

的變量的數目使用萬一你是Python的3.x中,這裏是從Python 2.7的源代碼:

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] 
相關問題