Menu
Coddy logo textTech

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 zamykany

Plik 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ów

Użyj własnego menedżera kontekstu:

with MyContext() as ctx:
    print("Inside the context")

Wynik:

Entering the context
Inside the context
Exiting the context

Utwó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 resources

Metoda __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.

challenge icon

Wyzwanie

Łatwy

W 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ę klasy Timer (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:

  1. Zapisywać czas rozpoczęcia przy wejściu do kontekstu
  2. Zapisywać czas zakończenia przy wyjściu
  3. 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
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Programowanie obiektowe

Poćwicz samodzielnie: Kompilator Python online