Heim  >  Artikel  >  Backend-Entwicklung  >  Die with-Anweisung und der Kontextmanager in Python

Die with-Anweisung und der Kontextmanager in Python

高洛峰
高洛峰Original
2017-03-01 14:15:401236Durchsuche

Als Kontextmanagerobjekt in Python können Sie die with-Anweisung verwenden. Die Verwendung des contextlib-Moduls, das den Kontextmanager bereitstellt, ist eine fortgeschrittene Fähigkeit in der Python-Programmierung Python. Zusammenfassung des maschinellen Lernens:

0. Über den Kontextmanager
Der Kontextmanager ist ein Objekt, das in der with-Anweisung verwendet werden kann und über die Methoden __enter__ und __exit__ verfügt.

with manager as var:
  do_something(var)

entspricht der Vereinfachung der folgenden Situation:

var = manager.__enter__()
try:
  do_something(var)
finally:
  manager.__exit__()

Mit anderen Worten: Das in PEP 343 definierte Kontextmanagerprotokoll ermöglicht die Abstraktion der langweiligen try...except...finally-Struktur in eine separate Klasse, sodass nur der do_something-Teil von Bedeutung bleibt.

__enter__-Methode wird zuerst aufgerufen. Es kann den Wert zurückgeben, der var zugewiesen ist. Der as-Teil ist optional: Wenn er nicht erscheint, wird der Rückgabewert von enter einfach ignoriert.
Der Code unter der with-Anweisung wird ausgeführt. Wie Try-Klauseln können sie entweder erfolgreich ausgeführt werden, abbrechen, fortfahren oder zurückkehren oder eine Ausnahme auslösen. In beiden Fällen wird nach Blockende die Methode __exit__ aufgerufen. Wenn eine Ausnahme ausgelöst wird, werden die Ausnahmeinformationen an __exit__ übergeben, was im nächsten Abschnitt erläutert wird. Normalerweise können Ausnahmen wie in einer final-Klausel ignoriert werden und werden nach dem Ende von __exit__ erneut ausgelöst.
Angenommen, wir möchten sicherstellen, dass eine Datei sofort nach Abschluss des Schreibvorgangs geschlossen wird:

>>> class closing(object):
...  def __init__(self, obj):
...   self.obj = obj
...  def __enter__(self):
...   return self.obj
...  def __exit__(self, *args):
...   self.obj.close()
>>> with closing(open('/tmp/file', 'w')) as f:
...  f.write('the contents\n')

Hier stellen wir sicher, dass der with-Block vorhanden ist Wird aufgerufen, wenn f.close() beendet wird. Da das Schließen einer Datei ein sehr häufiger Vorgang ist, ist diese Unterstützung bereits in der Dateiklasse vorhanden. Es verfügt über eine __exit__-Methode, die close aufruft und selbst als Kontextmanager fungiert.

>>> with open('/tmp/file', 'a') as f:
...  f.write('more contents\n')

Versuchen Sie es ... schließlich ist es üblich, Ressourcen freizugeben. Die verschiedenen Situationen werden ähnlich umgesetzt: Ressourcen werden in der __enter__-Phase erfasst, in der __exit__-Phase freigegeben und wenn eine Ausnahme geworfen wird, wird diese auch weitergeleitet. Genau wie Dateioperationen ist dies oft ein natürlicher Vorgang nach der Verwendung des Objekts und die integrierte Unterstützung macht ihn bequem. Mit jeder Version wird Python an mehr Stellen unterstützt.

1. So verwenden Sie den Kontextmanager:

So öffnen Sie eine Datei und schreiben „Hallo Welt“

filename="my.txt"
mode="w"
writer=open(filename,mode)
writer.write("hello world")
writer.close()

Wenn eine Ausnahme auftritt (z. B. wenn die Festplatte voll ist), besteht keine Möglichkeit, Zeile 5 auszuführen. Natürlich können wir try-finally-Anweisungsblöcke zum Packen verwenden:

writer=open(filename,mode)
try:
  writer.write("hello world")
finally:
  writer.close()

Wenn wir komplexe Operationen ausführen, wird die try-finally-Anweisung hässlich. Umschreiben mit der with-Anweisung:

with open(filename,mode) as writer:
  writer.write("hello world")

as bezieht sich auf den von der open()-Funktion zurückgegebenen Inhalt und weist ihn dem neuen Wert zu. with schließt die Aufgabe von try-finally ab.

2. Benutzerdefinierter Kontextmanager

Die with-Anweisung ähnelt try-finally und stellt einen Kontextmechanismus bereit. Um die with-Anweisung anzuwenden, muss die Klasse zwei integrierte Funktionen __enter__ und __exit__ bereitstellen. Ersteres wird ausgeführt, bevor der Hauptcode ausgeführt wird, und letzteres wird ausgeführt, nachdem der Hauptcode ausgeführt wird. Die Variablen nach as werden in der Funktion __enter__ zurückgegeben.

class echo():
  def output(self):
    print "hello world"
  def __enter__(self):
    print "enter"
    return self #可以返回任何希望返回的东西
  def __exit__(self,exception_type,value,trackback):
    print "exit"
    if exception_type==ValueError:
      return True
    else:
      return Flase
 
>>>with echo as e:
  e.output()


Ausgabe:

enter
hello world
exit

Die vollständige __exit__-Funktion lautet wie folgt:

def __exit__(self,exc_type,exc_value,exc_tb)

Darunter exc_type: Ausnahmetyp; exc_tb: Ausnahmeverfolgungsinformationen

Wenn __exit__ True zurückgibt, wird die Ausnahme nicht weitergegeben

3. contextlib-Modul

Die Rolle des contextlib-Moduls besteht darin, eine benutzerfreundlichere Lösung bereitzustellen Kontextmanager, der über Generator implementiert wird. Der Kontextmanager in contextlib dient als Dekorator, um einen Kontextverwaltungsmechanismus auf Funktionsebene bereitzustellen:

from contextlib import contextmanager
@contextmanager
def make_context():
  print 'enter'
  try:
    yield "ok"
  except RuntimeError,err:
    print 'error',err
  finally:
    print 'exit'
    
>>>with make_context() as value:
  print value


The Die Ausgabe lautet:

  enter
  ok
  exit

Darunter wird yield in try-finally geschrieben, um die Ausnahmesicherheit zu gewährleisten (kann Ausnahmen verarbeiten). Die Variable nach as wird von yield zurückgegeben. Die Anweisung vor yield kann als Operation vor der Ausführung des Codeblocks betrachtet werden, und die Operation nach yield kann als Operation in der Funktion __exit__ betrachtet werden.

Nehmen Sie die Thread-Sperre als Beispiel:

@contextlib.contextmanager
def loudLock():
  print 'Locking'
  lock.acquire()
  yield
  print 'Releasing'
  lock.release()
 
with loudLock():
  print 'Lock is locked: %s' % lock.locked()
  print 'Doing something that needs locking'
 
#Output:
#Locking
#Lock is locked: True
#Doing something that needs locking
#Releasing

4. contextlib.nested: Reduzieren Sie die Verschachtelung

Für:

with open(filename,mode) as reader:
  with open(filename1,mode1) as writer:
    writer.write(reader.read())

kann durch contextlib.nested vereinfacht werden:

with contextlib.nested(open(filename,mode),open(filename1,mode1)) as (reader,writer):
  writer.write(reader.read())

wird in Python 2.7 und höher durch eine neue Syntax ersetzt:

with open(filename,mode) as reader,open(filename1,mode1) as writer:
  writer.write(reader.read())

5. contextlib.closing( )

Die Dateiklasse unterstützt direkt die Kontextmanager-API, einige Objekte, die offene Handles darstellen, werden jedoch nicht unterstützt, z. B. die von urllib.urlopen() zurückgegebenen Objekte. Es gibt auch einige ältere Klassen, die die Methode close() verwenden, aber die Kontextmanager-API nicht unterstützen. Um sicherzustellen, dass das Handle geschlossen ist, müssen Sie mithilfe von close() (Aufruf der close-Methode der Klasse) einen Kontextmanager dafür erstellen.

import contextlib
class myclass():
  def __init__(self):
    print '__init__'
  def close(self):
    print 'close()'
   
with contextlib.closing(myclass()):
  print 'ok'


Ausgabe:

__init__
ok
close()


Weitere Artikel im Zusammenhang mit der with-Anweisung und dem Kontextmanager in Python finden Sie auf der chinesischen PHP-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