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) # 42Argumenty __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") # suppressedTł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 FalseMenedż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) # TrueImplementowanie 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
passSzybki 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
- Instrukcja with — szczegółowe omówienie
- Protokół __enter__ i __exit__
- contextlib: @contextmanager
- Praktyczne wzorce menedżerów kontekstu