Menedżery kontekstu
Część sekcji Programowanie obiektowe ścieżki Python w Coddy. Lekcja 41 z 64.
Menedżery kontekstu pozwalają przydzielać i zwalniać zasoby dokładnie wtedy, gdy są potrzebne. Zapewniają prawidłowe sprzątanie nawet w przypadku wystąpienia błędów.
Oto najczęstszy przykład użycia instrukcji with:
with open('example.txt', 'w') as file:
file.write('Hello, world!')
# Plik jest tutaj automatycznie zamykanyPlik zostaje automatycznie zamknięty po bloku, nawet jeśli wystąpi wyjątek.
Utwórz własny menedżer kontekstu, implementując metody __enter__ i __exit__:
class MyContext:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Exiting the context")
return False # Nie pomijaj wyjątkówUżyj własnego menedżera kontekstu:
with MyContext() as ctx:
print("Inside the context")Wynik:
Entering the context
Inside the context
Exiting the contextUtwórz bardziej praktyczny menedżer kontekstu dla połączeń z bazą danych:
class DatabaseConnection:
def __init__(self, db_name):
self.db_name = db_name
self.connection = None
def __enter__(self):
print(f"Connecting to {self.db_name}")
self.connection = f"Connection to {self.db_name}"
return self.connection
def __exit__(self, exc_type, exc_val, exc_tb):
print(f"Closing connection to {self.db_name}")
self.connection = None
with DatabaseConnection("users_db") as conn:
print(f"Using {conn}")
print("Performing database operations...")Obsługuj wyjątki w menedżerach kontekstu:
class SafeContext:
def __enter__(self):
print("Setting up resources")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("Cleaning up resources")
if exc_type:
print(f"An exception occurred: {exc_val}")
return False # Nie wyciszaj wyjątku
with SafeContext():
print("Working with resources")
# raise ValueError("Something went wrong") # Odkomentuj, aby przetestowaćWynik:
Connecting to users_db
Using Connection to users_db
Performing database operations...
Closing connection to users_db
Setting up resources
Working with resources
Cleaning up resourcesMetoda __exit__ otrzymuje trzy parametry:
exc_type: typ wyjątku (lub None)exc_val: wartość wyjątku (lub None)exc_tb: ślad stosu wyjątku (lub None)
Najważniejsza kwestia: Menedżery kontekstu używają metod __enter__ i __exit__ do zarządzania zasobami. Instrukcja with automatycznie wywołuje te metody, zapewniając prawidłowe przygotowanie i sprzątanie. Jest to szczególnie przydatne w przypadku plików, połączeń z bazą danych i innych zasobów, których sprzątanie musi być zagwarantowane.
Wyzwanie
ŁatwyW tym wyzwaniu zaimplementujesz klasę menedżera kontekstu, która mierzy czas, jaki upłynął między wejściem do bloku kontekstu a wyjściem z niego.
timer.py— zawiera implementację klasyTimer(to plik, który będziesz edytować)driver.py— zawiera kompleksowe przypadki testowe (nie modyfikuj go)
Zaimplementuj menedżera kontekstu Timer w pliku timer.py, postępując zgodnie z komentarzami TODO. Klasa powinna:
- Zapisywać czas rozpoczęcia przy wejściu do kontekstu
- Zapisywać czas zakończenia przy wyjściu
- Obliczać i wyświetlać czas, który upłynął
Spróbuj swoich sił
from timer import Timer
import time
# Obsługa przypadku testowego
test_case = input()
if test_case == "basic_test":
# Test podstawowego działania
with Timer():
# Symuluj wykonywanie pracy
time.sleep(2) # To sprawia, że program czeka przez 2 sekundy
elif test_case == "nested_contexts":
# Test zagnieżdżonych menedżerów kontekstu
with Timer():
time.sleep(1)
with Timer():
time.sleep(1)
elif test_case == "exception_handling":
# Test obsługi wyjątków w kontekście
try:
with Timer():
time.sleep(1)
raise ValueError("Test exception")
except ValueError as e:
print(f"Caught exception: {e}")
elif test_case == "zero_sleep":
# Test z minimalnym czasem uśpienia
with Timer():
time.sleep(0.001)
elif test_case == "multiple_timers":
# Test kilku timerów uruchamianych kolejno
with Timer():
time.sleep(1)
with Timer():
time.sleep(0.5)
with Timer():
time.sleep(2)
elif test_case == "as_decorator":
# Test timera w kontekście funkcji
def timed_function():
with Timer():
time.sleep(2)
timed_function()
else:
# Test domyślny – podstawowe działanie
with Timer():
# Symuluj wykonywanie pracy
time.sleep(2) # To sprawia, że program czeka przez 2 sekundy
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania obiektowego
Pliki zewnętrzneWprowadzenie do programowania obiektowegoKlasy a obiektyParametr selfMetodyAtrybutyMetoda konstruktora (__init__)Powtórzenie – prosty kalkulator4Dziedziczenie
Podstawy dziedziczeniaFunkcja super()Nadpisywanie metodDziedziczenie wielokrotneKolejność rozwiązywania metodPodsumowanie – hierarchia pracowników7Metody specjalne
Wprowadzenie do metod magicznychPrzeciążanie operatorówMagiczne metody kontenerówPowtórka – własna lista10Wzorce projektowe, część 1
Wprowadzenie do wzorców projektowychWzorzec SingletonWzorzec FactoryWzorzec ObserverWzorzec Strategy2Dekoratory
Wprowadzenie do dekoratorówDekorator propertyDekorator metody statycznejDekorator metody klasowej5Polimorfizm
Ponowne omówienie nadpisywania metodTypowanie kaczeKlasy i metody abstrakcyjneProjektowanie interfejsówPodsumowanie — kalkulator kształtów8Zaawansowane koncepcje programowania obiektowego
Kompozycja a dziedziczenieMiksyMetody statyczne i klasoweDekoratory klasMenedżery kontekstu11Wzorce projektowe, część 2
Wzorzec PolecenieWzorzec AdapterWzorzec DekoratorWzorzec Metoda szablonowaWzorzec StanWzorzec Kompozyt3Właściwości klas
Zmienne instancji a zmienne klasoweDekoratory właściwościAtrybuty prywatnePowtórzenie — menedżer kont bankowych6Hermetyzacja
Public, Protected, Private — pamięćModyfikatory dostępuUkrywanie informacjiDekoratory właściwości — zaawansowanePodsumowanie — system ewidencji uczniów12Projekt: System zarządzania biblioteką
Przegląd projektuKlasy Book i UserSystem wypożyczeńFunkcja wyszukiwaniaInterfejs administratoraTestowanie i integracjaPoćwicz samodzielnie: Kompilator Python online