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?

¿Fue útil?

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]
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top