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