Python Academy · Lektion

__enter__- og __exit__-protokollen

Opret context managers ved hjælp af dunder-protokollen.

Lektion 2 af 413 trin

__enter__- og __exit__-protokollen er en gratis Python Academy-lektion på CoddyKit. Dette er lektion 2 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Python Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Python Academy-kurset indeholder 4 lektioner i alt.

Protokollen for konteksthåndterere

Ethvert objekt, der definerer __enter__ og __exit__, er en konteksthåndterer og kan bruges sammen med with.

class Managed:
    def __enter__(self):
        print("entering")
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        print("exiting")
        return False

with Managed() as m:
    print("inside")

Returneringsværdi fra __enter__

__enter__ kaldes i starten af with-blokken. Dens returneringsværdi bindes til variablen efter as.

class Resource:
    def __enter__(self):
        self.value = 42
        return self  # bound to 'r'

    def __exit__(self, *args):
        self.value = None
        return False

with Resource() as r:
    print(r.value)  # 42

Argumenter til __exit__

__exit__(exc_type, exc_val, exc_tb) modtager oplysninger om undtagelsen, hvis der opstod en fejl. Hvis der ikke er nogen undtagelse, er alle tre None.

class Safe:
    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type is ValueError:
            print(f"Suppressed ValueError: {exc_val}")
            return True   # suppress the exception
        return False      # re-raise anything else

with Safe():
    raise ValueError("oops")  # suppressed

Undertrykke undtagelser

Returnér True fra __exit__ for at undertrykke undtagelsen. Returnér False (eller ingenting) for at lade den blive videresendt.

class Ignore:
    def __enter__(self): return self
    def __exit__(self, *args): return True  # swallow all exceptions

with Ignore():
    1 / 0

print("continues here")

Et eksempel med en databaseforbindelse

Et klassisk anvendelsestilfælde: Hent en forbindelse ved start, gennemfør eller rul tilbage, og luk ved afslutning.

class DBConn:
    def __enter__(self):
        self.conn = connect_db()
        return self.conn

    def __exit__(self, exc_type, exc_val, exc_tb):
        if exc_type:
            self.conn.rollback()
        else:
            self.conn.commit()
        self.conn.close()
        return False

En timer som konteksthåndterer

Mål den forløbne tid ved at registrere starten i __enter__ og beregne forskellen i __exit__.

import time

class Timer:
    def __enter__(self):
        self.start = time.perf_counter()
        return self

    def __exit__(self, *args):
        self.elapsed = time.perf_counter() - self.start
        print(f"Elapsed: {self.elapsed:.3f}s")
        return False

with Timer():
    sum(range(1_000_000))

Indlejring af konteksthåndterere

Flere konteksthåndterere kan kombineres på en enkelt with-linje.

with open("in.txt") as src, open("out.txt", "w") as dst:
    dst.write(src.read())

Genbrugelige kontra engangs-konteksthåndterere

Konteksthåndterere, hvis __enter__ tildeler en ny ressource hver gang, kan genbruges. Dem, der opbruger en intern tilstand (som en lås, der kun holdes én gang), kan muligvis ikke genbruges.

class Reusable:
    def __enter__(self):
        return []
    def __exit__(self, *a):
        return False

for _ in range(3):
    with Reusable() as lst:
        lst.append(1)
        print(lst)  # [1] each time

__aenter__ og __aexit__ (asynkrone)

For asynkrone konteksthåndterere skal du definere koroutinerne __aenter__ og __aexit__ og bruge async with.

class AsyncDB:
    async def __aenter__(self):
        self.conn = await connect()
        return self.conn

    async def __aexit__(self, *args):
        await self.conn.close()

# async with AsyncDB() as conn:
#     ...

Indpakning af filobjekter

Pythons filobjekter implementerer allerede protokollen for konteksthåndterere — kald aldrig f.close() manuelt.

with open("data.txt", "r") as f:
    data = f.read()
# file is closed here automatically
print(f.closed)  # True

Implementere en lås

Trådlåse er konteksthåndterere: __enter__ erhverver låsen, og __exit__ frigiver den.

import threading

lock = threading.Lock()

def update_shared():
    with lock:
        # critical section
        pass

Hurtigt tjek

Hvad skal __exit__ returnere for at undertrykke en undtagelse?

Opsummering

Implementér __enter__ og __exit__ for at oprette kontekstmanagere. Returnér ressourcen fra __enter__, og håndtér oprydning og undertrykkelse af undtagelser i __exit__.

Gratis at komme i gang

Lær Python med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
76
Lektioner
320

Ofte stillede spørgsmål

Er lektionen “__enter__- og __exit__-protokollen” gratis?

Ja — hele teksten til “__enter__- og __exit__-protokollen” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Python Academy-kurset, skal du opgradere til CoddyKit PRO. Python Academy-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “__enter__- og __exit__-protokollen”?

Opret context managers ved hjælp af dunder-protokollen. Du øver dig i Python Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Python Academy?

Der kræves ingen tidligere erfaring. Python Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 2 af 4.

Hvor lang tid tager lektionen “__enter__- og __exit__-protokollen”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Python Academy-lektion?

Ja. Alle Python Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. with-sætningen i dybden
  2. __enter__- og __exit__-protokollen
  3. contextlib: @contextmanager
  4. Praktiske mønstre for context managers
← Tilbage til Python Academy