Múltiples variables en un 'con' estado de cuenta?
-
23-08-2019 - |
Pregunta
¿Es posible declarar más de una variable utilizando una sentencia with
en Python?
Algo así 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 es la limpieza de dos recursos al mismo tiempo el problema?
Solución
Es posible en Python 3 desde v3.1 y < a href = "http://docs.python.org/dev/whatsnew/2.7.html#other-language-changes" rel = "noreferrer"> Python 2.7 . El nuevo with
sintaxis es compatible con varios gestores de contexto:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
A diferencia de la contextlib.nested
, esto garantiza que a
y b
tendrá de su __exit__()
llama incluso si C()
o es __enter__()
método lanza una excepción.
Otros consejos
contextlib.nested
apoya esta:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
Actualización:
Para citar la documentación, en relación con contextlib.nested
:
desuso desde la versión 2.7 : La declaración con-ahora es compatible con esta funcionalidad directamente (sin las peculiaridades propensas confuso de error).
Vea de Rafał Dowgird respuesta para más información.
Tenga en cuenta que si divide las variables en las líneas, debe utilizar barras invertidas para envolver los saltos de línea.
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(),
B(),
C()):
doSomething(a,b,c)
Desde tuplas no tienen un atributo __enter__
, se produce un error (undescriptive y no identifica el tipo de clase):
AttributeError: __enter__
Si intenta utilizar as
entre paréntesis, Python detecta el error en tiempo de análisis:
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
SyntaxError: no válido
https://bugs.python.org/issue12782 parece estar relacionado con este tema.
Creo que quiere 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)
Como Python 3.3, puede utilizar la clase ExitStack
del contextlib
módulo.
Se puede administrar un dinámico número de objetos sensibles al contexto, lo que significa que va a ser especialmente útil si usted no sabe la cantidad de archivos que se va a manejar.
El caso de uso canónica que se menciona en la documentación es la gestión de una serie dinámica 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
Este es 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]