più variabili in un 'con' affermazione?
-
23-08-2019 - |
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?
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]