Heim >Backend-Entwicklung >Python-Tutorial >Ausführliche Erklärung der Verwendung des Schlüsselworts with in Python

Ausführliche Erklärung der Verwendung des Schlüsselworts with in Python

高洛峰
高洛峰Original
2017-03-28 15:21:121609Durchsuche

In diesem Artikel werden hauptsächlich relevante Informationen zur detaillierten Verwendung des Schlüsselworts with in Python vorgestellt. In Python ist das Schlüsselwort with eine gute Möglichkeit, die Implementierung von Kontextprotokollobjekten für Sie zu verwalten it Sie können auf Folgendes verweisen ">

In Python 2.5 wurde das Schlüsselwort with hinzugefügt. Es macht das häufig verwendete Muster try ... außer ... endlich ... Sehr praktisch Wiederverwendung. Schauen Sie sich das klassischste Beispiel an:

In diesem Code wird die Datei unabhängig davon, was während der Ausführung des Codeblocks passiert, irgendwann geschlossen Bei der Ausführung schließt das Programm die geöffnete Datei, bevor die Ausnahme ausgelöst wird. Sehen Sie sich vor dem Initiieren einer Datenbank einen ähnlichen Code an:
with open('file.txt') as f:
  content = f.read()

Wenn der Vorgang zum Initiieren einer Transaktionsanforderung geändert wird, um das Schlüsselwort with zu unterstützen, reicht ein Code wie dieser aus:

Der Ausführungsprozess von with wird ausführlich erläutert und der obige Code wird implementiert auf zwei gängige Arten.

db.begin()
try:
  # do some actions
except:
  db.rollback()
  raise
finally:
  db.commit()

Der allgemeine Ausführungsprozess von with

with transaction(db):
  # do some actions
Ein grundlegender mit

Ausdruck

, seine Struktur ist wie folgt:

wobei: EXPR ein beliebiger Ausdruck sein kann; da VAR für seine allgemeine Ausführung optional ist. Der Prozess ist wie folgt:

Berechnen Sie EXPR und erhalten Sie einen Kontextmanager

with EXPR as VAR:
  BLOCK

Die Methode „exit()“ des Kontextmanagers wird gespeichert.
  1. Rufen Sie die Methode „enter()“ des Kontextmanagers auf.
  2. Wenn der with-Ausdruck als VAR enthält, dann wird EXPR der Rückgabewert VAR zugewiesen.
  3. Führen Sie den Ausdruck in BLOCK aus. Wenn während der Ausführung von BLOCK eine Ausnahme auftritt und das Programm beendet wird, werden der Ausnahmetyp, der Wert und der Traceback (dh der Rückgabewert von sys.exc_info()) als Parameter an die Methode „exit()“ übergeben. drei Keine werden übergeben.
  4. Stellen Sie diesen Prozess wie folgt im Code dar:
  5. Dieser Prozess hat mehrere Details:

  6. Wenn in der Kontextmanager Ohne eine der Methoden enter() oder exit() löst der Interpreter einen AttributeError aus.
  7. Wenn nach dem Auftreten einer Ausnahme in BLOCK die Methode „exit()“ einen Wert zurückgibt, der als „True“ angesehen werden kann, wird die Ausnahme nicht ausgelöst und der nachfolgende Code wird weiterhin ausgeführt.

    Als nächstes verwenden wir zwei Methoden, um den obigen Prozess zu implementieren.
Implementieren Sie die Kontextmanagerklasse

Die erste Möglichkeit besteht darin, eine Klasse zu implementieren, die eine Instanz
mgr = (EXPR)
exit = type(mgr).exit # 这里没有执行
value = type(mgr).enter(mgr)
exc = True
try:
  try:
    VAR = value # 如果有 as VAR
    BLOCK
  except:
    exc = False
    if not exit(mgr, *sys.exc_info()):
      raise
finally:
  if exc:
    exit(mgr, None, None, None)
Attribute

db und die für den Kontextmanager erforderlichen Methoden enter() und exit enthält () .


Nachdem man den Ausführungsprozess von with verstanden hat, ist diese Implementierung leicht zu verstehen. Die unten vorgestellte Implementierungsmethode ist viel komplizierter zu verstehen.

Verwendung von

Generatoren

Dekoratoren

In der Standardbibliothek von Python gibt es einen Dekorator, der über einen Generator einen Kontextmanager erhalten kann. Der Implementierungsprozess mithilfe des Generator-Dekorators ist wie folgt:

class transaction(object):
  def init(self, db):
    self.db = db
  def enter(self):
    self.db.begin()
  def exit(self, type, value, traceback):
    if type is None:
      db.commit()
    else:
      db.rollback()

Auf den ersten Blick ist diese Implementierung einfacher, ihr Mechanismus ist jedoch komplexer. Werfen wir einen Blick auf den Ausführungsprozess:

Nachdem der Python-Interpreter das Schlüsselwort yield erkennt, erstellt def eine Generator-Funktion , um die reguläre Funktion zu ersetzen (im (Klassendefinition: Ich verwende gerne Funktionen anstelle von Methoden).

from contextlib import contextmanager
@contextmanager
def transaction(db):
  db.begin()
  try:
    yield db
  except:
    db.rollback()
    raise
  else:
    db.commit()
Der Decorator-Kontextmanager wird aufgerufen und gibt eine Hilfsmethode zurück, die nach dem Aufruf eine GeneratorContextManager-Instanz generiert. Schließlich ruft der EXPR im with-Ausdruck die vom Contentmanager-Dekorator zurückgegebene Hilfsfunktion auf. Der

  1. with-Ausdruck ruft die Transaktion(db) auf, die tatsächlich die Hilfsfunktion aufruft. Die Hilfsfunktion ruft die Generatorfunktion auf, die einen Generator erstellt.

    Die Hilfsfunktion übergibt diesen Generator an GeneratorContextManager und erstellt eine Instanz von GeneratorContextManager als Kontextmanager.
  2. with 表达式调用实例对象的上下文管理器的 enter() 方法。

  3. enter() 方法中会调用这个生成器的 next() 方法。这时候,生成器方法会执行到 yield db 处停止,并将 db 作为 next() 的返回值。如果有 as VAR ,那么它将会被赋值给 VAR 。

  4. with 中的 BLOCK 被执行。

  5. BLOCK 执行结束后,调用上下文管理器的 exit() 方法。 exit() 方法会再次调用生成器的 next() 方法。如果发生 StopIteration 异常,则 pass 。

  6. 如果没有发生异常生成器方法将会执行 db.commit() ,否则会执行 db.rollback() 。

再次看看上述过程的代码大致实现:

def contextmanager(func):
  def helper(*args, **kwargs):
    return GeneratorContextManager(func(*args, **kwargs))
  return helper
class GeneratorContextManager(object):
  def init(self, gen):
    self.gen = gen
  def enter(self):
    try:
      return self.gen.next()
    except StopIteration:
      raise RuntimeError("generator didn't yield")
  def exit(self, type, value, traceback):
    if type is None:
      try:
        self.gen.next()
      except StopIteration:
        pass
      else:
        raise RuntimeError("generator didn't stop")
    else:
      try:
        self.gen.throw(type, value, traceback)
        raise RuntimeError("generator didn't stop after throw()")
      except StopIteration:
        return True
      except:
        if sys.exc_info()[1] is not value:
          raise

总结

Python的 with 表达式包含了很多Python特性。花点时间吃透 with 是一件非常值得的事情。

一些其他的例子

锁机制

@contextmanager
def locked(lock):
  lock.acquired()
  try:
    yield
  finally:
    lock.release()

标准输出重定向

@contextmanager
def stdout_redirect(new_stdout):
  old_stdout = sys.stdout
  sys.stdout = new_stdout
  try:
    yield
  finally:
    sys.stdout = old_stdout
with open("file.txt", "w") as f:
  with stdout_redirect(f):
    print "hello world"

Das obige ist der detaillierte Inhalt vonAusführliche Erklärung der Verwendung des Schlüsselworts with in Python. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
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