Eine ausführliche Erklärung der Python-Kontextmanager und mit Blöcken

巴扎黑
Freigeben: 2017-09-11 10:51:49
Original
999 Leute haben es durchsucht

Dieser Artikel stellt hauptsächlich die relevanten Informationen zum Python-Kontextmanager vor und hat einen gewissen Referenzwert. Interessierte Freunde können sich auf

Kontextmanager und den spezifischen Inhalt beziehen wie folgt

Der Zweck des Kontextmanagerobjekts besteht darin, die with-Anweisung zu verwalten, genau wie die Existenz des Iterators darin besteht, die for-Anweisung zu verwalten. Der Zweck der

with-Anweisung besteht darin, das try/finally-Muster zu vereinfachen. Dieser Modus wird verwendet, um sicherzustellen, dass eine bestimmte Operation ausgeführt wird, nachdem die Ausführung eines Codeabschnitts abgeschlossen ist. Auch wenn der Code aufgrund einer Ausnahme, einer Return-Anweisung oder eines sys.exit()-Aufrufs beendet wird, wird die angegebene Operation ausgeführt durchgeführt. Der Code in der final-Klausel wird normalerweise verwendet, um wichtige Ressourcen freizugeben oder einen vorübergehend geänderten Zustand wiederherzustellen.

==Das Kontextmanagerprotokoll enthält zwei Methoden: Enter und Exit==. Wenn die Ausführung der with-Anweisung beginnt, wird die Enter-Methode für das Kontextmanagerobjekt aufgerufen. Nachdem die Ausführung der with-Anweisung abgeschlossen ist, wird die Exit-Methode für das Kontextmanagerobjekt aufgerufen und übernimmt somit die Rolle der final-Klausel.

==Das Ergebnis der Ausführung des Ausdrucks nach with ist das Kontextmanagerobjekt. Das Binden des Werts an die Zielvariable (as-Klausel) ist das Ergebnis des Aufrufs der Enter-Methode für das Kontextmanagerobjekt==. Die as-Klausel der with-Anweisung ist optional. Für die open-Funktion muss eine as-Klausel hinzugefügt werden, um einen Verweis auf die Datei zu erhalten. Einige Kontextmanager geben jedoch „None“ zurück, da dem Benutzer kein nützliches Objekt zur Verfügung gestellt werden kann.


with open('mirror.py') as fp:
  ...
Nach dem Login kopieren

Benutzerdefinierte Kontextklasse:


class A:
  def __init__(self, name):
    self.name = name

  def __enter__(self):
    print('enter')
    return self.name

  def __exit__(self, exc_type, exc_val, exc_tb):
    print('gone')

with A('xiaozhe') as dt:
  print(dt)
Nach dem Login kopieren

contextlib-Modul

Es gibt auch einige Klassen und andere Funktionen im contextlib-Modul, die weiter verbreitet sind.

Schließen: Wenn das Objekt eine close()-Methode bereitstellt, aber das Enter/Exit-Protokoll nicht implementiert, können Sie diese Funktion verwenden, um einen Kontextmanager zu erstellen.
unterdrücken: Konstruieren Sie einen Kontextmanager, der bestimmte Ausnahmen vorübergehend ignoriert.
@contextmanager: ==Dieser Dekorator verwandelt eine einfache Generatorfunktion in einen Kontextmanager==, sodass keine Klasse erstellt werden muss, um das Managerprotokoll zu implementieren.
ContextDecorator: Dies ist eine Basisklasse, die zum Definieren klassenbasierter Kontextmanager verwendet wird. Dieser Kontextmanager kann auch zum Dekorieren von Funktionen verwendet werden, indem die gesamte Funktion in einem verwalteten Kontext ausgeführt wird
ExitStack: Dieser Kontextmanager kann mehrere Kontextmanager eingeben. Am Ende des with-Blocks ruft ExitStack die exit-Methoden jedes Kontextmanagers im Stapel in der Reihenfolge „Last-in-first-out“ auf.

== Am weitesten verbreitet ist der @contextmanager-Dekorator, also achten Sie besonders darauf. Dieser Dekorator ist auch deshalb verwirrend, weil er nichts mit Iteration zu tun hat, sondern die Yield-Anweisung == verwendet.

Verwendung von @contextmanager

Der @contextmanager-Dekorator kann die Menge an Boilerplate-Code reduzieren, der zum Erstellen eines Kontextmanagers erforderlich ist, anstatt eine vollständige Klasse zu schreiben, die Ein- und Ausstiegsmethoden definiert Sie müssen lediglich einen Generator mit einer Yield-Anweisung implementieren, um den Wert zu generieren, den die Enter-Methode zurückgeben soll.

In einem mit @contextmanager dekorierten Generator besteht die Funktion der yield-Anweisung darin, den Definitionskörper der Funktion in zwei Teile zu unterteilen: ==yield Der gesamte Code vor der Anweisung beginnt am Anfang des with-Blocks (d. h. der Interpreter ruft die Enter-Methode auf), der Code nach der yield-Anweisung führt == am Ende des with-Blocks aus (d. h. wenn die Exit-Methode aufgerufen wird).


import contextlib

@contextlib.contextmanager
def test(name):
  print('start')
  yield name
  print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')
Nach dem Login kopieren

Implementierungsprinzip

contextlib.contextmanager decorator verpackt die Funktion in eine Klasse, die die Enter- und Exit-Methoden implementiert . Der Name der Klasse ist _GeneratorContextManager.

Die Enter-Methode dieser Klasse hat die folgenden Funktionen:
1. Rufen Sie die Generatorfunktion auf und speichern Sie das Generatorobjekt (hier heißt es gen).
2. Rufen Sie next(gen) auf und führen Sie es an der Position des yield-Schlüsselworts aus.
3. Geben Sie den von next(gen) erzeugten Wert zurück, damit der erzeugte Wert an die Zielvariable in der with/as-Anweisung gebunden werden kann.

Wenn der with-Block beendet wird, führt die Exit-Methode Folgendes aus:

Überprüfen Sie, ob die Ausnahme an exc_type übergeben wurde. Wenn ja, rufen Sie gen.throw auf. Ausnahme) wird eine Ausnahme in der Zeile ausgelöst, die das Schlüsselwort yield im Definitionshauptteil der Generatorfunktion enthält.
2. Andernfalls rufen Sie next(gen) auf, um mit der Ausführung des Codes nach der yield-Anweisung im Definitionskörper der Generatorfunktion fortzufahren.

Ausnahmebehandlung

Um dem Interpreter mitzuteilen, dass die Ausnahme behandelt wurde, gibt die Exit-Methode True zurück und der Interpreter unterdrückt die Ausnahme. Wenn die Exit-Methode nicht explizit einen Wert zurückgibt, ruft der Interpreter „None“ ab und löst die Ausnahme aus.

Bei Verwendung des @contextmanager-Dekorators ist das Standardverhalten das Gegenteil: Die vom Dekorator bereitgestellte Exit-Methode geht davon aus, dass alle an den Generator gesendeten Ausnahmen behandelt wurden und Ausnahmen daher unterdrückt werden sollten. Wenn Sie nicht möchten, dass @contextmanager Ausnahmen unterdrückt, müssen Sie die Ausnahme in der dekorierten Funktion explizit erneut auslösen.

Im obigen Code liegt ein Fehler vor: Wenn eine Ausnahme im with-Block ausgelöst wird, fängt der Python-Interpreter sie ab und löst sie dann erneut im Yield-Ausdruck der Testfunktion aus. Da jedoch kein Code zur Fehlerbehandlung vorhanden ist, bricht die Testfunktion ab.

使用 @contextmanager 装饰器时,要把 yield 语句放在 try/finally 语句中,因为我们永远不知道上下文管理器的用户会在 with 块中做什么。


import contextlib

@contextlib.contextmanager
def test(name):
  print('start')

  try:
    yield name
  except:
    raise ValueError('error')
  finally:
    print('end')

with test('zhexiao123') as dt:
  print(dt)
  print('doing something')
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonEine ausführliche Erklärung der Python-Kontextmanager und mit Blöcken. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage