Can I declare multiple variables using the with statement in Python?
It's like:
from __future__ import with_statement with open("out.txt","wt"), open("in.txt") as file_out, file_in: for line in file_in: file_out.write(line)
... or are the two resources being cleaned up and having problems at the same time?
#1 building
From v3.1 and Python 2.7 At first, It can be in Implementation in Python 3 . new with syntax Multiple context managers are supported:
with A() as a, B() as b, C() as c: doSomething(a,b,c)
Unlike contextlib.nested, this ensures that a and b will have their own call to \\\\\\\\\\\.
#2 building
Because Python 3.3, you can use classes ExitStack from contextlib Modular.
It manages a dynamic number of context aware objects, which means it's particularly useful if you don't know how many files to process.
The specification use case mentioned in the document is to manage a dynamic number of files.
with 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
This is a general example:
from contextlib import ExitStack class X: num = 1 def __init__(self): self.num = X.num X.num += 1 def __repr__(self): cls = type(self) return '{cls.__name__}{self.num}'.format(cls=cls, self=self) def __enter__(self): print('enter {!r}'.format(self)) return self.num def __exit__(self, exc_type, exc_value, traceback): print('exit {!r}'.format(self)) return True xs = [X() for _ in range(3)] with ExitStack() as stack: print(stack._exit_callbacks) nums = [stack.enter_context(x) for x in xs] print(stack._exit_callbacks) print(stack._exit_callbacks) print(nums)
Output:
deque([]) enter X1 enter X2 enter X3 deque([<function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86158>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f861e0>, <function ExitStack._push_cm_exit.<locals>._exit_wrapper at 0x7f5c95f86268>]) exit X3 exit X2 exit X1 deque([]) [1, 2, 3]
#3 building
Note that if you split a variable into rows, you must use a backslash to wrap the line.
with A() as a, \ B() as b, \ C() as c: doSomething(a,b,c)
Parentheses don't work because Python creates a tuple.
with (A(), B(), C()): doSomething(a,b,c)
An error (unrecognized and unrecognized class type) occurs because the tuple is missing the 'enter' attribute:
AttributeError: __enter__
If you try to use as brackets, python catches errors in analysis:
with (A() as a, B() as b, C() as c): doSomething(a,b,c)
Syntax error: invalid syntax
https://bugs.python.org/issue12782 It seems to have something to do with this problem.
#4 building
I think you want to do this:
from __future__ import with_statement with open("out.txt","wt") as file_out: with open("in.txt") as file_in: for line in file_in: file_out.write(line)
#5 building
contextlib.nested Support this:
import contextlib with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in): ...
To update:
Reference documents, about contextlib.nested :
Not recommended since version 2.7: the with statement now directly supports this feature (no error prone quirks).
For more information, see Rafa fongird's answer .