with while open manager español else decorators context python with-statement

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.