Python Language
Kontexthanterare (“med” -förklaring)
Sök…
Introduktion
Medan Pythons kontekthanterare används i stor utsträckning, förstår få syftet bakom deras användning. Dessa uttalanden, som vanligtvis används för att läsa och skriva filer, hjälper applikationen att spara systemminne och förbättra resurshanteringen genom att säkerställa att specifika resurser endast används för vissa processer. Detta ämne förklarar och demonstrerar användningen av Pythons kontexthanterare.
Syntax
- med "context_manager" (som "alias") (, "context_manager" (som "alias")?) *:
Anmärkningar
Kontexthanterare definieras i PEP 343 . De är avsedda att användas som en mer kortfattad mekanism för resurshantering än try ... finally
konstruerar. Den formella definitionen är som följer.
I denna PEP tillhandahåller sammanhangshanterare
__enter__()
och__exit__()
-metoder som åberopas vid inresa till och ut ur kroppen med uttalandet.
Därefter definieras with
uttalandet enligt följande.
with EXPR as VAR: BLOCK
Översättningen av ovanstående uttalande är:
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)
Introduktion till kontekthanterare och med uttalande
En kontexthanterare är ett objekt som meddelas när ett kontext (ett kodblock) startar och slutar . Du använder ofta en with
uttalandet. Det tar hand om anmälan.
Till exempel är filobjekt kontexthanterare. När ett sammanhang slutar stängs filobjektet automatiskt:
open_file = open(filename)
with open_file:
file_contents = open_file.read()
# the open_file object has automatically been closed.
Exemplet ovan är vanligtvis förenklas genom att använda as
nyckelord:
with open(filename) as open_file:
file_contents = open_file.read()
# the open_file object has automatically been closed.
Allt som slutar exekveringen av blocket får kontexthanterarens utgångsmetod att kallas. Detta inkluderar undantag och kan vara användbart när ett fel gör att du för tidigt lämnar en öppen fil eller anslutning. Att lämna ett skript utan att stänga filer / anslutningar korrekt är en dålig idé, vilket kan orsaka dataförlust eller andra problem. Genom att använda en context manager kan du säkerställa att försiktighetsåtgärder alltid vidtas för att förhindra skada eller förlust på detta sätt. Den här funktionen lades till i Python 2.5.
Tilldela till ett mål
Många kontexthanterare returnerar ett objekt när de matas in. Du kan tilldela det objektet till ett nytt namn i with
uttalandet.
Om du till exempel använder en databasanslutning i en with
sats kan du få ett markörobjekt:
with database_connection as cursor:
cursor.execute(sql_query)
Filobjekt returnerar sig själva, detta gör det möjligt att både öppna filobjektet och använda det som en sammanhangshanterare i ett uttryck:
with open(filename) as open_file:
file_contents = open_file.read()
Skriva din egen context manager
En context manager är alla objekt som implementerar två magiska metoder __enter__()
och __exit__()
(även om det också kan implementera andra metoder):
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
Om sammanhanget avslutas med ett undantag, kommer informationen om detta undantag att skickas som en trippel exc_type
, exc_value
, traceback
(dessa är samma variabler som returneras av sys.exc_info()
). Om sammanhanget avslutas normalt är alla dessa tre argument None
.
Om ett undantag inträffar och överförs till __exit__
metoden, kan metoden återgå till True
för att undertrycka undantaget, eller så kommer undantaget att höjas igen i slutet av __exit__
funktionen.
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
Observera att i det andra exemplet trots att ett undantag inträffar i mitten av kroppen med med-uttalandet, __exit__
fortfarande, innan undantaget sprider sig till det yttre räckvidden.
Om du bara behöver en __exit__
metod kan du returnera instansen för context manager:
class MyContextManager:
def __enter__(self):
return self
def __exit__(self):
print('something')
Skriva din egen contextmanager med hjälp av generatorsyntax
Det är också möjligt att skriva en kontexthanterare med hjälp av generatorsyntax tack vare contextlib.contextmanager
dekoratören:
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))
producerar:
Enter
Right in the middle with cm = 3
Exit
Dekoratören förenklar uppgiften att skriva en kontexthanterare genom att konvertera en generator till en. Allt innan avkastningsuttrycket blir metoden __enter__
, det __enter__
värdet blir värdet som returneras av generatorn (som kan bindas till en variabel i med-satset), och allt efter avkastningsuttrycket blir metoden __exit__
.
Om ett undantag måste hanteras av context manager, kan ett try..except..finally
-block skrivas i generatorn och alla undantag som tas upp with
-block kommer att hanteras av detta undantagsblock.
@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)
Detta producerar:
Enter
Dividing by cm = 0
Caught error
Cleaning up
Exit
Flera kontexthanterare
Du kan öppna flera innehållshanterare samtidigt:
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')
Det har samma effekt som häckande sammanhangshanterare:
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')
Hantera resurser
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__()
-metoden ställer in objektet, i detta fall ställer du in filnamnet och läget för att öppna filen. __enter__()
öppnar och returnerar filen och __exit__()
stänger bara den.
Med hjälp av dessa magiska metoder ( __enter__
, __exit__
) kan du implementera objekt som enkelt kan användas with
med-uttalandet.
Använd File-klassen:
for _ in range(10000):
with File('foo.txt', 'w') as f:
f.write('foo')