Note: I am aware of the
with open('f1') as f1, open('f2') as f2: ...
syntax. This is a different question.
Given a list of strings file_names
is there a way using with
/as
to open every file name in that using a single line. Something such as:
with [open(fn) for fn in file_names] as files: # use the list of files
which of course doesn't work as it attempts to use the context manager on a list. The length of the list may not be known until run-time, such as sys.argv[1:]
A context manager usually takes care of setting up some resource, e.g. opening a connection, and automatically handles the clean up when we are done with it. Probably, the most common use case is opening a file. The code above will open the file and will keep it open until we are out of the with statement.
To open multiple files using "with open" in Python, we can separate each file with a comma. We call open with 'r' to open foo. txt and bar.
Context managers allow you to allocate and release resources precisely when you want to. The most widely used example of context managers is the with statement. Suppose you have two related operations which you'd like to execute as a pair, with a block of code in between.
The with statement in Python is a quite useful tool for properly managing external resources in your programs. It allows you to take advantage of existing context managers to automatically handle the setup and teardown phases whenever you're dealing with external resources or with operations that require those phases.
If you have access to Python 3.3+, there is a special class designed exactly for this purpose: the ExitStack
. It works just like you'd expect:
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
How about this?
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
Output is:
[<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>]
Notice, they are open inside the with context and closed outside.
This is using the Python context manager API.
EDIT: It seems like this already exists but is deprecated: See contextlib and this SO question. Use it like this:
import contextlib with contextlib.nested(*[open(fn, 'w') for fn in arr]) as files: print files print files
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With