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?

War es hilfreich?

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]
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top