0Pricing
Python Academy · Lekcja

Protokół __enter__ i __exit__

Proszę budować menedżery kontekstu za pomocą protokołu dunder.

Protokół __enter__ i __exit__ to bezpłatna lekcja Python Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Python Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Python Academy zawiera 4 lekcji w sumie.

Protokół menedżera kontekstu

Każdy obiekt definiujący __enter__ i __exit__ jest menedżerem kontekstu i może być używany z 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")

Wartość zwracana przez __enter__

__enter__ jest wywoływane na początku bloku with. Jego wartość zwracana jest przypisywana do zmiennej znajdującej się po 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

Argumenty __exit__

__exit__(exc_type, exc_val, exc_tb) otrzymuje informacje o wyjątku, jeśli wystąpił błąd. Jeśli nie wystąpił wyjątek, wszystkie trzy wartości to 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

Tłumienie wyjątków

Zwrócenie True z __exit__ tłumi wyjątek. Zwrócenie False lub brak wartości zwracanej pozwala na jego propagację.

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

with Ignore():
    1 / 0

print("continues here")

Przykład połączenia z bazą danych

Klasyczny przypadek użycia: na wejściu pobierane jest połączenie, a przy wychodzeniu następuje zatwierdzenie lub wycofanie transakcji oraz zamknięcie połączenia.

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

Menedżer kontekstu mierzący czas

Upływ czasu można zmierzyć, zapisując moment rozpoczęcia w __enter__ i obliczając różnicę w __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))

Zagnieżdżanie menedżerów kontekstu

Wiele menedżerów kontekstu można połączyć w jednym wierszu instrukcji with.

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

Menedżery wielokrotnego i jednokrotnego użycia

Menedżery kontekstu, których __enter__ za każdym razem przydziela nowy zasób, można stosować wielokrotnie. Te, które wyczerpują wewnętrzny stan, na przykład blokada utrzymywana tylko raz, mogą nie nadawać się do ponownego użycia.

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__ i __aexit__ (asynchroniczne)

W przypadku asynchronicznych menedżerów kontekstu należy zdefiniować korutyny __aenter__ i __aexit__ oraz używać 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:
#     ...

Opakowywanie obiektów plików

Obiekty plików w Pythonie już implementują protokół menedżera kontekstu — nie należy ręcznie wywoływać f.close().

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

Implementowanie blokady

Blokady wątków są menedżerami kontekstu: __enter__ przejmuje blokadę, a __exit__ ją zwalnia.

import threading

lock = threading.Lock()

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

Szybki test

Co powinno zwracać __exit__, aby pominąć wyjątek?

Podsumowanie

Zaimplementuj __enter__ i __exit__, aby utworzyć menedżery kontekstu. Zwracaj zasób z __enter__, a w __exit__ obsługuj sprzątanie i pomijanie wyjątków.

Często zadawane pytania

Czy lekcja „Protokół __enter__ i __exit__” jest bezpłatna?

Tak — pełny tekst „Protokół __enter__ i __exit__” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Python Academy, przejdź na CoddyKit PRO. Kurs Python Academy zawiera 4 lekcji w sumie.

Co nauczysz się w „Protokół __enter__ i __exit__”?

Proszę budować menedżery kontekstu za pomocą protokołu dunder. Ćwiczysz Python Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Python Academy?

Nie wymagamy żadnego doświadczenia. Python Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Protokół __enter__ i __exit__”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Python Academy?

Tak. Każda lekcja Python Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Instrukcja with — szczegółowe omówienie
  2. Protokół __enter__ i __exit__
  3. contextlib: @contextmanager
  4. Praktyczne wzorce menedżerów kontekstu
← Powrót do Python Academy