Toán tử with

Python SELF VI
Mức độ , Bài học
Có sẵn

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 exceptfinally.

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__()__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__()__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__()__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_valexc_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")
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION