Python Language
Kontextmanager ("mit" -Anweisung)
Suche…
Einführung
Während die Kontextmanager von Python weit verbreitet sind, wissen nur wenige den Zweck ihrer Verwendung. Diese Anweisungen, die häufig beim Lesen und Schreiben von Dateien verwendet werden, unterstützen die Anwendung bei der Einsparung von Systemspeicher und verbessern die Ressourcenverwaltung, indem sie sicherstellen, dass bestimmte Ressourcen nur für bestimmte Prozesse verwendet werden. In diesem Thema wird die Verwendung der Kontextmanager von Python erläutert und veranschaulicht.
Syntax
- mit "context_manager" (als "Alias") (, "Context_manager" (als "Alias")?) *:
Bemerkungen
Kontextmanager sind in PEP 343 definiert. Sie sind als prägnanter Mechanismus für das Ressourcenmanagement gedacht, als try ... finally
Konstrukte. Die formale Definition lautet wie folgt.
In diesem PEP stellen
__enter__()
Methoden__enter__()
und__exit__()
, die beim Eintritt in den Rumpf der with-Anweisung aufgerufen werden.
Anschließend wird die with
Anweisung wie folgt definiert.
with EXPR as VAR: BLOCK
Die Übersetzung der obigen Aussage lautet:
mgr = (EXPR) exit = type(mgr).__exit__ # Not calling it yet value = type(mgr).__enter__(mgr) exc = True try: try: VAR = value # Only if "as VAR" is present BLOCK except: # The exceptional case is handled here exc = False if not exit(mgr, *sys.exc_info()): raise # The exception is swallowed if exit() returns true finally: # The normal and non-local-goto cases are handled here if exc: exit(mgr, None, None, None)
Einführung in Kontextmanager und die with-Anweisung
Ein Kontextmanager ist ein Objekt, das benachrichtigt wird, wenn ein Kontext (ein Codeblock) beginnt und endet . Sie verwenden häufig eine mit der with
Anweisung. Es kümmert sich um die Benachrichtigung.
Beispielsweise sind Dateiobjekte Kontextmanager. Wenn ein Kontext endet, wird das Dateiobjekt automatisch geschlossen:
open_file = open(filename)
with open_file:
file_contents = open_file.read()
# the open_file object has automatically been closed.
Das obige Beispiel wird normalerweise mit dem Schlüsselwort as
vereinfacht:
with open(filename) as open_file:
file_contents = open_file.read()
# the open_file object has automatically been closed.
Alles, was die Ausführung des Blocks beendet, führt zum Aufruf der Exit-Methode des Kontextmanagers. Dies schließt Ausnahmen ein und kann nützlich sein, wenn ein Fehler dazu führt, dass Sie eine geöffnete Datei oder Verbindung vorzeitig beenden. Das Beenden eines Skripts ohne ordnungsgemäßes Schließen von Dateien / Verbindungen ist eine schlechte Idee, die zu Datenverlust oder anderen Problemen führen kann. Durch die Verwendung eines Kontextmanagers können Sie sicherstellen, dass immer Vorkehrungen getroffen werden, um auf diese Weise Schäden oder Verluste zu vermeiden. Diese Funktion wurde in Python 2.5 hinzugefügt.
Einem Ziel zuweisen
Viele Kontextmanager geben bei der Eingabe ein Objekt zurück. Sie können dieses Objekt in der with
Anweisung einem neuen Namen zuweisen.
Wenn Sie beispielsweise eine Datenbankverbindung in einer with
Anweisung verwenden, erhalten Sie ein Cursorobjekt:
with database_connection as cursor:
cursor.execute(sql_query)
Dateiobjekte geben sich selbst zurück, wodurch das Dateiobjekt geöffnet und als Kontextmanager in einem Ausdruck verwendet werden kann:
with open(filename) as open_file:
file_contents = open_file.read()
Schreiben Sie Ihren eigenen Kontextmanager
Ein Kontextmanager ist ein Objekt, das zwei magische Methoden __enter__()
und __exit__()
implementiert (obwohl es auch andere Methoden implementieren kann):
class AContextManager():
def __enter__(self):
print("Entered")
# optionally return an object
return "A-instance"
def __exit__(self, exc_type, exc_value, traceback):
print("Exited" + (" (with an exception)" if exc_type else ""))
# return True if you want to suppress the exception
Wenn der Kontext mit einer Ausnahme beendet wird , wird die Information über diese Ausnahme als Triple geführt werden exc_type
, exc_value
, traceback
(das sind die gleichen Variablen wie die zurück sys.exc_info()
Funktion). Wenn der Kontext normal beendet wird, sind alle drei Argumente None
.
Wenn eine Ausnahme auftritt und an die __exit__
Methode übergeben wird, kann die Methode True
, um die Ausnahme zu unterdrücken, oder die Ausnahme wird am Ende der __exit__
Funktion erneut __exit__
.
with AContextManager() as a:
print("a is %r" % a)
# Entered
# a is 'A-instance'
# Exited
with AContextManager() as a:
print("a is %d" % a)
# Entered
# Exited (with an exception)
# Traceback (most recent call last):
# File "<stdin>", line 2, in <module>
# TypeError: %d format: a number is required, not str
Beachten Sie, dass im zweiten Beispiel der __exit__
Handler weiterhin ausgeführt wird, obwohl eine Ausnahme in der Mitte des __exit__
der mit-Anweisung __exit__
, bevor die Ausnahme an den äußeren Bereich weitergegeben wird.
Wenn Sie nur eine __exit__
Methode benötigen, können Sie die Instanz des Kontextmanagers zurückgeben:
class MyContextManager:
def __enter__(self):
return self
def __exit__(self):
print('something')
Schreiben Sie Ihren eigenen Kontextmanager mit der Generatorsyntax
Dank des Decorators contextlib.contextmanager
ist es auch möglich, einen Kontextmanager unter Verwendung der Generatorsyntax zu schreiben:
import contextlib
@contextlib.contextmanager
def context_manager(num):
print('Enter')
yield num + 1
print('Exit')
with context_manager(2) as cm:
# the following instructions are run when the 'yield' point of the context
# manager is reached.
# 'cm' will have the value that was yielded
print('Right in the middle with cm = {}'.format(cm))
produziert:
Enter
Right in the middle with cm = 3
Exit
Der Dekorator vereinfacht das Schreiben eines Kontextmanagers durch Konvertieren eines Generators in einen. Alles vor dem Ertragsausdruck wird zur __enter__
Methode, der __enter__
wird zum vom Generator zurückgegebenen Wert (der an eine Variable in der with-Anweisung gebunden werden kann), und alles, was nach dem Ertragsausdruck geht, wird zur __exit__
Methode.
Wenn eine Ausnahmebedingung vom Kontextmanager behandelt werden muss, kann ein try..except..finally
Block in den Generator geschrieben werden, und jede im with
try..except..finally
Ausnahme wird von diesem Ausnahmeblock behandelt.
@contextlib.contextmanager
def error_handling_context_manager(num):
print("Enter")
try:
yield num + 1
except ZeroDivisionError:
print("Caught error")
finally:
print("Cleaning up")
print("Exit")
with error_handling_context_manager(-1) as cm:
print("Dividing by cm = {}".format(cm))
print(2 / cm)
Dies erzeugt:
Enter
Dividing by cm = 0
Caught error
Cleaning up
Exit
Mehrere Kontextmanager
Sie können mehrere Content Manager gleichzeitig öffnen:
with open(input_path) as input_file, open(output_path, 'w') as output_file:
# do something with both files.
# e.g. copy the contents of input_file into output_file
for line in input_file:
output_file.write(line + '\n')
Dies hat den gleichen Effekt wie das Schachteln von Kontextmanagern:
with open(input_path) as input_file:
with open(output_path, 'w') as output_file:
for line in input_file:
output_file.write(line + '\n')
Ressourcen verwalten
class File():
def __init__(self, filename, mode):
self.filename = filename
self.mode = mode
def __enter__(self):
self.open_file = open(self.filename, self.mode)
return self.open_file
def __exit__(self, *args):
self.open_file.close()
__init__()
Methode __init__()
richtet das Objekt ein. In diesem Fall __init__()
den Dateinamen und den Modus für das Öffnen der Datei ein. __enter__()
öffnet die Datei und __exit__()
sie zurück. __exit__()
schließt sie einfach.
Mit diesen magischen Methoden ( __enter__
, __exit__
) können Sie Objekte implementieren, die problemlos with
der with-Anweisung verwendet werden können.
Dateiklasse verwenden:
for _ in range(10000):
with File('foo.txt', 'w') as f:
f.write('foo')