4.1 Закриття файла і обробка помилок
Іноді при читанні файла виникають помилки або винятки, і файл залишається незакритим. Це потенційно може призвести до витоку пам'яті або витоку file handler'ів. Тому роботу з файлом потрібно обертати в блок try-except.
Допустимо, у вас був код:
file = open('example.txt', 'a') # Відкриваємо файл
file.write("This is a new line added to the file.")
file.close() # Закриваємо файл
Його потрібно загорнути в блок try-except:
try:
file = open('example.txt', 'a') # Відкриваємо файл
file.write("This is a new line added to the file.")
file.close() # Закриваємо файл
except FileNotFoundError:
print("File not found")
file.close() # Закриваємо файл
Щоб двічі не писати метод close(), можна винести його в блок finally:
try:
file = open('example.txt', 'a') # Відкриваємо файл
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Закриваємо файл
Цей код виглядає красиво, але… не працює, оскільки змінна file визначена тільки в блоці try і недоступна з блоків except і finally.
Тому нам потрібно визначити змінну на рівень вище:
file = None
try:
file = open('example.txt', 'a') # Відкриваємо файл
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Закриваємо файл
Це рішення краще, але у нього теж є недоліки. Наприклад, якщо файл так і не буде відкритий, то в змінній file залишиться None. І тоді спроба закрити файл викличе помилку — буде спроба звернутися до методу close() у неіснуючого об'єкта.
Тому нам потрібно додати перевірку перед викликом методу close():
file = None
try:
file = open('example.txt', 'a') # Відкриваємо файл
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
if file:
file.close() # Закриваємо файл
Якщо ви здивовані тим, що 3 рядки коду перетворилися в 9, то ви не самі. На щастя, вже є готове рішення для цієї проблеми, про яке ми поговоримо далі.
4.2 Оператор with
Оператор with в Python надає зручний спосіб управління ресурсами, такими як файли, забезпечуючи їх автоматичне закриття після завершення блоку with. Це спрощує код і запобігає витокам ресурсів, таких як незакриті файли.
Загальний синтаксис оператора with:
with вираз as змінна:
робота з змінною
Оператор with використовується для обгортання виконання блоку коду менеджером контексту. При використанні оператора with Python автоматично викликає методи __enter__() і __exit__() об'єкта менеджера контексту, що спрощує управління ресурсами.
Приклад використання with для роботи з файлами:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
У цьому прикладі файл example.txt відкривається в режимі запису, а ім'я файла зв'язується з змінною file. Блок коду всередині with автоматично закриває файл після виконання всіх операцій запису.
4.3 Автоматичне закриття файла
Однією з головних переваг використання оператора with є автоматичне закриття файла після завершення блоку коду. Це відбувається навіть у випадку виникнення винятку, що робить код більш безпечним і надійним.
Приклад автоматичного закриття файла:
try:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
# Виняток, щоб перевірити, що файл все одно закриється
raise Exception("Something went wrong")
except Exception as e:
print(f"Caught an exception: {e}")
# У цьому місці файл вже закритий
Завжди використовуйте оператор with при роботі з файлами. Це просто і дозволяє уникнути багатьох помилок.
4.4 Під капотом оператора with
В основі роботи оператора with лежать методи __enter__() і __exit__(), які повинні бути реалізовані в класі, що використовується як менеджер контексту.
Для того, щоб об'єкт міг використовуватись з оператором with, він повинен реалізовувати методи __enter__() і __exit__(). Ці методи визначають поведінку при вході і виході з контексту.
Метод __enter__()
Метод __enter__() викликається при вході в блок with. Він виконує ініціалізацію ресурсу і повертає об'єкт, який буде прив'язаний до змінної, вказаної після as.
Метод __exit__()
Метод __exit__() викликається при виході з блоку with. Він виконує завершальні дії, такі як звільнення ресурсів або закриття файлів. Метод приймає три аргумента: exc_type, exc_val і exc_tb, які містять інформацію про виняток, якщо він стався.
-
exc_type: тип винятку (наприклад,ZeroDivisionError). -
exc_val: значення винятку (наприклад, повідомлення про помилку). exc_tb: трасування стека винятку.
Якщо метод __exit__() повертає True, то виняток буде придушено. Якщо повертає False, виняток буде повторно викликано.
Приклад:
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 # Виняток не придушується
with MyContextManager() as manager:
print("Inside the with block")
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ