4.1 Zamknięcie pliku i obsługa błędów
Czasem podczas czytania pliku występują błędy lub wyjątki i plik zostaje niezamknięty. To może prowadzić do wycieku pamięci lub wycieku file handler’ów. Dlatego pracę z plikiem warto opakować w blok try-except.
Załóżmy, że miałeś taki kod:
file = open('example.txt', 'a') # Otwieramy plik
file.write("This is a new line added to the file.")
file.close() # Zamykamy plik
Trzeba go opakować w blok try-except:
try:
file = open('example.txt', 'a') # Otwieramy plik
file.write("This is a new line added to the file.")
file.close() # Zamykamy plik
except FileNotFoundError:
print("File not found")
file.close() # Zamykamy plik
Aby nie pisać metody close() dwa razy, można ją przenieść do bloku finally:
try:
file = open('example.txt', 'a') # Otwieramy plik
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Zamykamy plik
Ten kod wygląda schludnie, ale… nie działa, ponieważ zmienna file jest zdefiniowana tylko w bloku try i nie jest dostępna z bloków except i finally.
W związku z tym musimy zdefiniować zmienną na wyższym poziomie:
file = None
try:
file = open('example.txt', 'a') # Otwieramy plik
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Zamykamy plik
To rozwiązanie jest lepsze, ale ma swoje wady. Na przykład, jeśli plik nie zostanie otwarty, to w zmiennej file pozostanie None. I wtedy próba zamknięcia pliku wywoła błąd — będzie próba wywołania metody close() dla nieistniejącego obiektu.
W związku z tym musimy dodać sprawdzenie przed wywołaniem metody close():
file = None
try:
file = open('example.txt', 'a') # Otwieramy plik
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
if file:
file.close() # Zamykamy plik
Jeśli jesteś zdziwiony, że 3 linijki kodu zamieniły się w 9, to nie jesteś sam. Na szczęście już jest gotowe rozwiązanie tego problemu, o którym powiemy dalej.
4.2 Operator with
Operator with w Pythonie daje wygodny sposób zarządzania zasobami, takimi jak pliki, zapewniając ich automatyczne zamykanie po zakończeniu bloku with. To upraszcza kod i zapobiega wyciekom zasobów, takich jak niezapisane pliki.
Ogólna składnia operatora with:
with wyrażenie as zmienna:
praca z zmienną
Operator with służy do opakowywania wykonania bloku kodu menedżerem kontekstu. Przy użyciu operatora with Python automatycznie wywołuje metody __enter__() i __exit__() obiektu menedżera kontekstu, co upraszcza zarządzanie zasobami.
Przykład użycia with do pracy z plikami:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
W tym przykładzie plik example.txt jest otwierany w trybie zapisu, a nazwa pliku jest przypisywana do zmiennej file. Blok kodu wewnątrz with automatycznie zamyka plik po wykonaniu wszystkich operacji zapisu.
4.3 Automatyczne zamknięcie pliku
Jednym z głównych zalet użycia operatora with jest automatyczne zamknięcie pliku po zakończeniu bloku kodu. To się dzieje nawet w przypadku wystąpienia wyjątku, co czyni kod bardziej bezpiecznym i niezawodnym.
Przykład automatycznego zamknięcia pliku:
try:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
# Wyjątek, aby sprawdzić, czy plik i tak się zamknie
raise Exception("Something went wrong")
except Exception as e:
print(f"Caught an exception: {e}")
# W tym momencie plik jest już zamknięty
Zawsze używaj operatora with przy pracy z plikami. To proste i pozwala uniknąć wielu błędów.
4.4 Pod maską operatora with
Podstawą działania operatora with są metody __enter__() i __exit__(), które muszą być zrealizowane w klasie, używanej jako menedżer kontekstu.
Aby obiekt mógł być używany z operatorem with, musi realizować metody __enter__() i __exit__(). Te metody definiują zachowanie przy wejściu i wyjściu z kontekstu.
Metoda __enter__()
Metoda __enter__() jest wywoływana przy wejściu do bloku with. Wykonuje inicjalizację zasobu i zwraca obiekt, który będzie powiązany ze zmienną, określoną po as.
Metoda __exit__()
Metoda __exit__() jest wywoływana przy wyjściu z bloku with. Wykonuje działania końcowe, takie jak zwolnienie zasobów lub zamknięcie plików. Metoda przyjmuje trzy argumenty: exc_type, exc_val i exc_tb, które zawierają informacje o wyjątku, jeśli wystąpił.
-
exc_type: typ wyjątku (na przykładZeroDivisionError). -
exc_val: wartość wyjątku (na przykład komunikat o błędzie). exc_tb: ślad stosu wyjątku.
Jeśli metoda __exit__() zwraca True, to wyjątek zostanie zignorowany. Jeśli zwraca False, wyjątek zostanie ponownie wzbudzony.
Przykład:
class MyContextManager:
def __enter__(self):
print("Entering the context")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
if exc_type:
print(f"An exception occurred: {exc_type}, {exc_val}")
return False # Wyjątek nie jest pomijany
with MyContextManager() as manager:
print("Inside the with block")
GO TO FULL VERSION