Mehrere Variablen in einer ‚mit‘ Aussage?
-
23-08-2019 - |
Frage
Ist es möglich, mehr als eine Variable zu deklarieren eine with
Anweisung in Python?
So etwas wie:
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)
... oder zwei Ressourcen, um das Problem zugleich Reinigung?
Lösung
Es ist möglich, in Python 3 seit v3.1 und < a href = "http://docs.python.org/dev/whatsnew/2.7.html#other-language-changes" rel = "noreferrer"> Python 2.7 . Die neue with
Syntax unterstützt mehr Kontext-Manager:
with A() as a, B() as b, C() as c:
doSomething(a,b,c)
Im Gegensatz zu dem contextlib.nested
garantiert dies, dass a
und b
ihre __exit__()
der gerufenen hat, auch wenn C()
oder es ist __enter__()
Methode löst eine Ausnahme aus.
Andere Tipps
contextlib.nested
unterstützt dies:
import contextlib
with contextlib.nested(open("out.txt","wt"), open("in.txt")) as (file_out, file_in):
...
Update:
Um die Dokumentation zu zitieren, in Bezug auf contextlib.nested
:
Veraltet seit Version 2.7 : Die mit-Anweisung dies jetzt unterstützt direkt Funktionalität (ohne die verwirrende fehleranfällig Macken).
Rafał Dowgird Antwort für weitere Informationen.
Beachten Sie, dass die Variablen in Zeilen aufgeteilt, Sie Schrägstriche verwenden, müssen die Zeilenumbrüche zu wickeln.
with A() as a, \
B() as b, \
C() as c:
doSomething(a,b,c)
Klammern funktionieren nicht, da Python ein Tupel erzeugt statt.
with (A(),
B(),
C()):
doSomething(a,b,c)
Da Tupel ein __enter__
Attribut fehlt, erhalten Sie einen Fehler (undescriptive und nicht Klassentyp identifizieren):
AttributeError: __enter__
Wenn Sie versuchen, in Klammern verwenden as
, Python fängt den Fehler zur Analysezeit:
with (A() as a,
B() as b,
C() as c):
doSomething(a,b,c)
Syntax: ungültige Syntax
https://bugs.python.org/issue12782 scheint zu diesem Thema zusammenhängen.
Ich glaube, Sie wollen, dies zu tun, statt:
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)
Seit Python 3.3, können Sie die Klasse ExitStack
von der contextlib
Modul.
Es kann eine dynamisch verwalten Anzahl der kontextsensitiven Objekte, was bedeutet, dass es besonders nützlich erweisen, wenn Sie nicht wissen, wie viele Dateien, die Sie behandeln werden.
Die kanonische Use-Case, die in der Dokumentation erwähnt wird, ist eine dynamische Anzahl von Dateien zu verwalten.
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
Hier ist ein allgemeines Beispiel:
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)
Ausgabe:
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]