4.1 Đóng file và xử lý lỗi
Đôi khi khi đọc file có thể phát sinh lỗi hoặc ngoại lệ, và file không
được đóng lại. Điều này tiềm ẩn nguy cơ rò rỉ bộ nhớ hoặc
rò rỉ file handler
. Do vậy công việc với file cần phải được bao bọc trong
khối try-except
.
Giả sử bạn có đoạn mã:
file = open('example.txt', 'a') # Mở file
file.write("This is a new line added to the file.")
file.close() # Đóng file
Cần bọc nó trong khối try-except
:
try:
file = open('example.txt', 'a') # Mở file
file.write("This is a new line added to the file.")
file.close() # Đóng file
except FileNotFoundError:
print("File not found")
file.close() # Đóng file
Để không phải viết phương thức close()
hai lần, bạn có thể đưa nó vào khối
finally
:
try:
file = open('example.txt', 'a') # Mở file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Đóng file
Mã này trông rất đẹp, nhưng… không hoạt động vì biến file
chỉ được định nghĩa trong khối try
và không thể truy cập từ các khối except
và finally
.
Do vậy chúng ta cần định nghĩa biến ở cấp cao hơn:
file = None
try:
file = open('example.txt', 'a') # Mở file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
file.close() # Đóng file
Giải pháp này tốt hơn, nhưng nó cũng có nhược điểm. Ví dụ, nếu file
không được mở, thì biến file
sẽ giữ giá trị None
. Và khi đó
cố gắng đóng file sẽ gây ra lỗi — sẽ là cố gắng gọi phương thức
close()
trên một đối tượng không tồn tại.
Do vậy ta cần thêm kiểm tra trước khi gọi phương thức close()
:
file = None
try:
file = open('example.txt', 'a') # Mở file
file.write("This is a new line added to the file.")
except FileNotFoundError:
print("File not found")
finally:
if file:
file.close() # Đóng file
Nếu bạn ngạc nhiên vì 3 dòng mã đã trở thành 9, thì bạn không phải người duy nhất. May mắn thay, đã có giải pháp sẵn cho vấn đề này, chúng ta sẽ nói tới ngay sau đây.
4.2 Toán tử with
Toán tử with
trong Python cung cấp cách tiện lợi để quản lý
tài nguyên, chẳng hạn như file, đảm bảo chúng tự động được đóng
sau khi hoàn thành khối with
. Điều này đơn giản hóa mã và ngăn chặn sự rò rỉ
tài nguyên, chẳng hạn như file chưa được đóng.
Cú pháp chung của toán tử with
:
with biểu thức as biến:
thao tác với biến
Toán tử with
được sử dụng để
bao bọc thực thi của một khối mã với trình quản lý ngữ cảnh. Khi
sử dụng toán tử with
, Python tự động
gọi các phương thức __enter__()
và
__exit__()
của đối tượng trình quản lý ngữ cảnh, đơn giản hóa
việc quản lý tài nguyên.
Ví dụ sử dụng with
để làm việc với file:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
Trong ví dụ này, file example.txt
được mở ở chế độ ghi, và tên
file được liên kết với biến file
. Khối mã
bên trong with
sẽ tự động đóng file sau khi thực hiện xong các thao tác ghi.
4.3 Tự động đóng file
Một trong những lợi ích chính của việc sử dụng
toán tử with
là khả năng tự động
đóng file sau khi hoàn thành khối mã. Điều này xảy ra
ngay cả khi có ngoại lệ phát sinh, giúp
mã an toàn và đáng tin cậy hơn.
Ví dụ về tự động đóng file:
try:
with open('example.txt', 'w') as file:
file.write("Hello, World!\n")
file.write("This is a test file.\n")
# Ngoại lệ để kiểm tra rằng file vẫn sẽ được đóng
raise Exception("Something went wrong")
except Exception as e:
print(f"Caught an exception: {e}")
# Vào thời điểm này file đã được đóng
Hãy luôn sử dụng toán tử with
khi
làm việc với file. Điều này đơn giản và giúp tránh nhiều lỗi.
4.4 Dưới mui của toán tử with
Dưới cơ bản của hoạt động của toán tử with
là các phương thức __enter__()
và
__exit__()
, chúng cần phải được hiện thực trong lớp sẽ được dùng
làm trình quản lý ngữ cảnh.
Để một đối tượng có thể sử dụng được với
toán tử with
, nó phải hiện thực các phương thức __enter__()
và
__exit__()
. Những phương thức này xác định hành vi khi vào và
ra khỏi ngữ cảnh.
Phương thức __enter__()
Phương thức __enter__()
được gọi khi vào khối with
.
Nó thực hiện khởi tạo tài nguyên và trả về đối tượng sẽ
được liên kết với biến, chỉ định sau as
.
Phương thức __exit__()
Phương thức __exit__()
được gọi khi thoát khỏi khối with
. Nó thực hiện
các hành động kết thúc, như giải phóng tài nguyên hoặc đóng
file. Phương thức nhận ba tham số: exc_type
, exc_val
và exc_tb
,
chúng chứa thông tin về ngoại lệ nếu nó đã xảy ra.
-
exc_type
: loại ngoại lệ (ví dụ,ZeroDivisionError
). -
exc_val
: giá trị ngoại lệ (ví dụ, thông báo lỗi). exc_tb
: trace gốc của ngoại lệ.
Nếu phương thức __exit__()
trả về True
,
thì ngoại lệ sẽ bị ngăn chặn. Nếu trả về
False
, ngoại lệ sẽ được kích hoạt lại.
Ví dụ:
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 # Ngoại lệ không bị ngăn chặn
with MyContextManager() as manager:
print("Inside the with block")
GO TO FULL VERSION