Domanda

E 'possibile dichiarare più di una variabile utilizzando un'istruzione with in Python?

Qualcosa di simile:

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 è ripulire due risorse allo stesso tempo il problema?

È stato utile?

Soluzione

E 'possibile in Python 3 dal v3.1 e < a href = "http://docs.python.org/dev/whatsnew/2.7.html#other-language-changes" rel = "noreferrer"> Python 2.7 . Il nuovo with sintassi supporta più gestori di contesto:

with A() as a, B() as b, C() as c:
    doSomething(a,b,c)

A differenza del contextlib.nested, questo garantisce che a e b avranno il loro __exit__() chiamato anche se C() o è il metodo __enter__() solleva un'eccezione.

Altri suggerimenti

contextlib.nested supporta questo:

import contextlib

with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):

   ...

Aggiornamento:
Per citare la documentazione, per quanto riguarda contextlib.nested :

  

deprecato dalla versione 2.7 : Il con-statement ora supporta questo   funzionalità direttamente (senza gli errori confusa peculiarità inclini).

Rafał Dowgird risposta per ulteriori informazioni.

Si noti che se si divide le variabili in linee, è necessario utilizzare le barre rovesciate per avvolgere le nuove righe.

with A() as a, \
     B() as b, \
     C() as c:
    doSomething(a,b,c)

Le parentesi non funzionano, poiché Python crea una tupla invece.

with (A(),
      B(),
      C()):
    doSomething(a,b,c)

Dal momento che le tuple non hanno un attributo __enter__, si ottiene un errore (undescriptive e non consente di identificare il tipo di classe):

AttributeError: __enter__

Se si tenta di utilizzare as tra parentesi, Python rileva l'errore in fase di analisi:

with (A() as a,
      B() as b,
      C() as c):
    doSomething(a,b,c)
  

SyntaxError: invalid syntax

https://bugs.python.org/issue12782 sembra essere correlato a questo problema.

Credo che si vuole fare questo, invece:

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)

Dato che Python 3.3, è possibile utilizzare il ExitStack dal contextlib modulo.

E 'possibile gestire un dinamica numero degli oggetti context-aware, il che significa che si rivelerà particolarmente utile se non si conosce il numero di file che si sta per gestire.

Il caso d'uso canonico menzionato nella documentazione è gestito una serie dinamica di file.

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

Ecco un esempio generico:

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]
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top