while - Múltiples variables en Python ''con'' declaración
with python español (5)
¿Es posible declarar más de una variable usando una declaración with
en Python?
Algo como:
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)
... o está limpiando dos recursos al mismo tiempo que el problema?
Creo que quieres hacer esto en su lugar:
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)
Desde Python 3.3, puede usar la clase ExitStack
del módulo contextlib
.
Puede administrar un número dinámico de objetos sensibles al contexto, lo que significa que será especialmente útil si no sabe cuántos archivos va a manejar.
El caso de uso canónico que se menciona en la documentación es administrar un número dinámico de archivos.
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
Aquí hay un ejemplo genérico:
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)
Salida:
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]
Es posible en Python 3 desde v3.1 y Python 2.7 . El nuevo with
sintaxis soporta múltiples gestores de contexto:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
A diferencia de contextlib.nested
, esto garantiza que a
y b
tendrán su __exit__()
llamado incluso si C()
o su método __enter__()
genera una excepción.
Tenga en cuenta que si divide las variables en líneas, debe usar barras invertidas para ajustar las nuevas líneas.
with A() as a, /
B() as b, /
C() as c:
doSomething(a,b,c)
Los paréntesis no funcionan, ya que Python crea una tupla en su lugar.
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
Como las tuplas carecen de un atributo __enter__
, __enter__
un error (no __enter__
y no identifica el tipo de clase):
AttributeError: __enter__
contextlib.nested
apoya esto:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
Actualizar:
Para citar la documentación, referente a contextlib.nested
:
En desuso desde la versión 2.7 : el with-statement ahora admite esta funcionalidad directamente (sin las confusas peculiaridades propensas al error).
Ver la respuesta de Rafał Dowgird para más información.