512 Stimmen

Wofür ist die Python-Anweisung "with" gedacht?

Ich bin auf die Python with Erklärung heute zum ersten Mal abgegeben. Ich benutze Python schon seit einigen Monaten und wusste nicht einmal, dass es existiert! In Anbetracht seines etwas obskuren Status dachte ich, es wäre eine Frage wert:

  1. Was ist die Python with Anweisung für die sie verwendet werden soll?
  2. Was tun verwenden Sie es?
  3. Gibt es irgendwelche Fallstricke, die ich beachten muss, oder gängige Anti-Patterns im Zusammenhang mit der Verwendung? Gibt es Fälle, in denen es besser ist try..finally als with ?
  4. Warum wird sie nicht häufiger eingesetzt?
  5. Welche Standardbibliotheksklassen sind mit ihr kompatibel?

450voto

Tamás Punkte 45697
  1. Ich glaube, diese Frage wurde bereits von anderen Benutzern vor mir beantwortet, daher füge ich sie nur der Vollständigkeit halber hinzu: Die with Anweisung vereinfacht die Behandlung von Ausnahmen, indem sie allgemeine Vorbereitungs- und Bereinigungsaufgaben in sogenannten Kontextmanager . Weitere Einzelheiten sind zu finden unter PEP 343 . Zum Beispiel die open Anweisung ist ein eigenständiger Kontextmanager, mit dem Sie eine Datei öffnen und offen halten können, solange sich die Ausführung im Kontext der with Anweisung, in der Sie sie verwendet haben, und schließen Sie sie, sobald Sie den Kontext verlassen, unabhängig davon, ob Sie ihn aufgrund einer Ausnahme oder während des normalen Kontrollflusses verlassen haben. Die with Anweisung kann daher auf ähnliche Weise verwendet werden wie die RAII-Muster in C++: eine Ressource wird von der with Anweisung und beim Verlassen des Büros freigegeben with Kontext.

  2. Einige Beispiele sind: Öffnen von Dateien mit with open(filename) as fp: Erwerb von Sperren mit with lock: (donde lock ist eine Instanz von threading.Lock ). Sie können auch Ihre eigenen Kontextmanager erstellen, indem Sie die contextmanager Dekorateur aus contextlib . Ich verwende dies zum Beispiel oft, wenn ich das aktuelle Verzeichnis vorübergehend wechseln und dann wieder dorthin zurückkehren muss, wo ich vorher war:

    from contextlib import contextmanager
    import os
    
    @contextmanager
    def working_directory(path):
        current_dir = os.getcwd()
        os.chdir(path)
        try:
            yield
        finally:
            os.chdir(current_dir)
    
    with working_directory("data/stuff"):
        # do something within data/stuff
    # here I am back again in the original working directory

    Hier ist ein weiteres Beispiel, das vorübergehend umleitet sys.stdin , sys.stdout y sys.stderr zu einem anderen Dateihandle und stellt sie später wieder her:

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def redirected(**kwds):
        stream_names = ["stdin", "stdout", "stderr"]
        old_streams = {}
        try:
            for sname in stream_names:
                stream = kwds.get(sname, None)
                if stream is not None and stream != getattr(sys, sname):
                    old_streams[sname] = getattr(sys, sname)
                    setattr(sys, sname, stream)
            yield
        finally:
            for sname, stream in old_streams.iteritems():
                setattr(sys, sname, stream)
    
    with redirected(stdout=open("/tmp/log.txt", "w")):
         # these print statements will go to /tmp/log.txt
         print "Test entry 1"
         print "Test entry 2"
    # back to the normal stdout
    print "Back to normal stdout again"

    Und schließlich ein weiteres Beispiel, bei dem ein temporärer Ordner angelegt und beim Verlassen des Kontexts aufgeräumt wird:

    from tempfile import mkdtemp
    from shutil import rmtree
    
    @contextmanager
    def temporary_dir(*args, **kwds):
        name = mkdtemp(*args, **kwds)
        try:
            yield name
        finally:
            shutil.rmtree(name)
    
    with temporary_dir() as dirname:
        # do whatever you want

102voto

systempuntoout Punkte 68725

Ich würde zwei interessante Vorträge vorschlagen:

  • PEP 343 Die "mit"-Anweisung
  • Effbot Verstehen der Python-Anweisung "with"-Anweisung

1. Die with Anweisung wird verwendet, um die Ausführung eines Blocks mit Methoden zu umhüllen, die von einem Kontextmanager definiert werden. Dies ermöglicht gemeinsame try...except...finally Nutzungsmuster zur bequemen Wiederverwendung gekapselt werden.

2. Sie könnten etwas wie folgt tun:

with open("foo.txt") as foo_file:
    data = foo_file.read()

OU

from contextlib import nested
with nested(A(), B(), C()) as (X, Y, Z):
   do_something()

OR (Python 3.1)

with open('data') as input_file, open('result', 'w') as output_file:
   for line in input_file:
     output_file.write(parse(line))

OU

lock = threading.Lock()
with lock:
    # Critical section of code

3. Ich kann hier kein Antipattern erkennen.
Zitat Eintauchen in Python :

probieren endlich ist gut. mit ist besser.

4. Ich vermute, das hängt mit der Gewohnheit der Programmierer zusammen, die try..catch..finally Anweisung aus anderen Sprachen.

46voto

Tendayi Mawushe Punkte 24821

Die Python with Anweisung ist eine integrierte Sprachunterstützung der Resource Acquisition Is Initialization Idiom, das in C++ häufig verwendet wird. Es soll den sicheren Erwerb und die Freigabe von Betriebssystemressourcen ermöglichen.

Le site with Anweisung erstellt Ressourcen innerhalb eines Bereichs/Blocks. Sie schreiben Ihren Code unter Verwendung der Ressourcen innerhalb des Blocks. Wenn der Block beendet wird, werden die Ressourcen sauber freigegeben, unabhängig vom Ergebnis des Codes im Block (d.h. ob der Block normal oder aufgrund einer Ausnahme beendet wird).

Viele Ressourcen in der Python-Bibliothek, die sich an das Protokoll halten, das von der with Anweisung und kann daher sofort mit ihr verwendet werden. Jeder kann jedoch Ressourcen erstellen, die in einer with-Anweisung verwendet werden können, indem er das gut dokumentierte Protokoll implementiert: PEP 0343

Verwenden Sie es immer dann, wenn Sie in Ihrer Anwendung Ressourcen erwerben, die explizit freigegeben werden müssen, wie z. B. Dateien, Netzwerkverbindungen, Sperren und dergleichen.

29voto

JudoWill Punkte 4571

Der Vollständigkeit halber füge ich noch meinen nützlichsten Anwendungsfall für with Erklärungen.

Ich beschäftige mich viel mit wissenschaftlichen Berechnungen, und für einige Tätigkeiten benötige ich die Decimal Bibliothek für Berechnungen mit beliebiger Genauigkeit. Für einen Teil meines Codes benötige ich hohe Präzision und für die meisten anderen Teile brauche ich weniger Präzision.

Ich setze meine Standardpräzision auf eine niedrige Zahl und verwende dann with um eine genauere Antwort für einige Abschnitte zu erhalten:

from decimal import localcontext

with localcontext() as ctx:
    ctx.prec = 42   # Perform a high precision calculation
    s = calculate_something()
s = +s  # Round the final result back to the default precision

Ich verwende dies häufig beim Hypergeometrischen Test, der die Division großer Zahlen zur Bildung von Faktorzahlen erfordert. Bei Berechnungen im genomischen Maßstab muss man auf Rundungs- und Überlauffehler achten.

28voto

John La Rooy Punkte 278961

Ein Beispiel für ein Antipattern könnte die Verwendung der with innerhalb einer Schleife, wenn es effizienter wäre, die with außerhalb der Schleife

zum Beispiel

for row in lines:
    with open("outfile","a") as f:
        f.write(row)

gegen

with open("outfile","a") as f:
    for row in lines:
        f.write(row)

Die erste Möglichkeit ist das Öffnen und Schließen der Datei für jede row was zu Leistungsproblemen führen kann, verglichen mit der zweiten Möglichkeit, bei der die Datei nur einmal geöffnet und geschlossen wird.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X