Exception Handling (Try/Except)
1. Giới thiệu
Phần tiêu đề “1. Giới thiệu”Exception (ngoại lệ) là lỗi xảy ra khi chương trình đang chạy. Nếu không xử lý, chương trình sẽ dừng đột ngột.
Exception Handling (xử lý ngoại lệ) giúp chương trình:
- Không bị crash khi gặp lỗi
- Xử lý lỗi một cách có kiểm soát
- Hiển thị thông báo lỗi thân thiện với người dùng
2. Try/Except cơ bản
Phần tiêu đề “2. Try/Except cơ bản”2.1 - Cú pháp
Phần tiêu đề “2.1 - Cú pháp”try: # Code có thể gây lỗi risky_operation()except: # Code xử lý khi có lỗi print("Có lỗi xảy ra!")2.2 - Ví dụ: Chia cho 0
Phần tiêu đề “2.2 - Ví dụ: Chia cho 0”# Không xử lý lỗi - Chương trình crash!# result = 10 / 0 # ZeroDivisionError
# Có xử lý lỗi - Chương trình tiếp tục chạytry: result = 10 / 0 print(result)except: print("Không thể chia cho 0!")
print("Chương trình vẫn chạy tiếp")2.3 - Ví dụ: Chuyển đổi kiểu dữ liệu
Phần tiêu đề “2.3 - Ví dụ: Chuyển đổi kiểu dữ liệu”user_input = "abc"
try: number = int(user_input) print(f"Số bạn nhập: {number}")except: print("Vui lòng nhập một số hợp lệ!")3. Bắt Exception cụ thể
Phần tiêu đề “3. Bắt Exception cụ thể”3.1 - Tại sao cần bắt exception cụ thể?
Phần tiêu đề “3.1 - Tại sao cần bắt exception cụ thể?”Bắt exception cụ thể giúp:
- Xử lý từng loại lỗi khác nhau
- Code dễ đọc và maintain hơn
- Debug dễ dàng hơn
3.2 - Cú pháp
Phần tiêu đề “3.2 - Cú pháp”try: risky_operation()except ValueError: print("Lỗi giá trị không hợp lệ")except ZeroDivisionError: print("Lỗi chia cho 0")3.3 - Ví dụ
Phần tiêu đề “3.3 - Ví dụ”try: age = int(input("Nhập tuổi: ")) result = 100 / age print(f"Kết quả: {result}")except ValueError: print("Tuổi phải là một số!")except ZeroDivisionError: print("Tuổi không thể là 0!")4. Các loại Exception phổ biến
Phần tiêu đề “4. Các loại Exception phổ biến”| Exception | Khi nào xảy ra | Ví dụ |
|---|---|---|
ValueError |
Giá trị không đúng kiểu | int("abc") |
ZeroDivisionError |
Chia cho 0 | 10 / 0 |
TypeError |
Sai kiểu dữ liệu | "hello" + 5 |
IndexError |
Index vượt quá phạm vi | [1,2,3][10] |
KeyError |
Key không tồn tại | dict["key"] |
FileNotFoundError |
File không tồn tại | open("xyz.txt") |
AttributeError |
Thuộc tính không tồn tại | "hello".xyz() |
NameError |
Biến chưa được định nghĩa | print(x) |
Ví dụ từng loại
Phần tiêu đề “Ví dụ từng loại”# ValueErrortry: number = int("abc")except ValueError as e: print(f"ValueError: {e}")
# IndexErrortry: my_list = [1, 2, 3] print(my_list[10])except IndexError as e: print(f"IndexError: {e}")
# KeyErrortry: my_dict = {"name": "Alice"} print(my_dict["age"])except KeyError as e: print(f"KeyError: {e}")5. Lấy thông tin lỗi với ‘as’
Phần tiêu đề “5. Lấy thông tin lỗi với ‘as’”try: result = 10 / 0except ZeroDivisionError as error: print(f"Lỗi: {error}") print(f"Loại lỗi: {type(error).__name__}")Kết quả:
Lỗi: division by zeroLoại lỗi: ZeroDivisionError6. Bắt nhiều Exception
Phần tiêu đề “6. Bắt nhiều Exception”6.1 - Bắt từng loại riêng
Phần tiêu đề “6.1 - Bắt từng loại riêng”try: number = int(input("Nhập số: ")) result = 100 / number print(result)except ValueError: print("Vui lòng nhập số!")except ZeroDivisionError: print("Không thể chia cho 0!")6.2 - Bắt nhiều loại cùng lúc
Phần tiêu đề “6.2 - Bắt nhiều loại cùng lúc”try: # Code passexcept (ValueError, TypeError, ZeroDivisionError) as e: print(f"Lỗi: {e}")6.3 - Bắt tất cả Exception (không khuyến khích)
Phần tiêu đề “6.3 - Bắt tất cả Exception (không khuyến khích)”try: # Code passexcept Exception as e: print(f"Có lỗi: {e}")7. Else và Finally
Phần tiêu đề “7. Else và Finally”7.1 - Else: Chạy khi KHÔNG có lỗi
Phần tiêu đề “7.1 - Else: Chạy khi KHÔNG có lỗi”try: number = int(input("Nhập số: "))except ValueError: print("Số không hợp lệ!")else: print(f"Bạn đã nhập: {number}") print("Không có lỗi xảy ra!")7.2 - Finally: Luôn luôn chạy
Phần tiêu đề “7.2 - Finally: Luôn luôn chạy”try: file = open("data.txt", "r") content = file.read()except FileNotFoundError: print("File không tồn tại!")else: print("Đọc file thành công!")finally: print("Khối này luôn chạy") # Đóng file nếu đã mở try: file.close() except: pass7.3 - Cấu trúc đầy đủ
Phần tiêu đề “7.3 - Cấu trúc đầy đủ”try: # Code có thể gây lỗi result = 10 / 2except ZeroDivisionError: # Xử lý lỗi chia 0 print("Lỗi chia 0")except ValueError: # Xử lý lỗi giá trị print("Lỗi giá trị")else: # Chạy nếu KHÔNG có lỗi print(f"Kết quả: {result}")finally: # Luôn luôn chạy print("Hoàn thành!")8. Raise Exception
Phần tiêu đề “8. Raise Exception”8.1 - Tự tạo Exception
Phần tiêu đề “8.1 - Tự tạo Exception”def divide(a, b): if b == 0: raise ValueError("Không thể chia cho 0!") return a / b
try: result = divide(10, 0)except ValueError as e: print(f"Lỗi: {e}")8.2 - Re-raise Exception
Phần tiêu đề “8.2 - Re-raise Exception”try: result = 10 / 0except ZeroDivisionError: print("Ghi log lỗi...") raise # Ném lại exception để xử lý ở nơi khác9. Custom Exception
Phần tiêu đề “9. Custom Exception”Tạo Exception riêng cho ứng dụng:
class AgeError(Exception): """Exception cho tuổi không hợp lệ""" pass
def check_age(age): if age < 0: raise AgeError("Tuổi không thể âm!") if age > 150: raise AgeError("Tuổi quá lớn!") return True
try: check_age(-5)except AgeError as e: print(f"Lỗi tuổi: {e}")10. Ví dụ thực tế
Phần tiêu đề “10. Ví dụ thực tế”Ví dụ 1: Validate input số
Phần tiêu đề “Ví dụ 1: Validate input số”def get_number(prompt): while True: try: value = int(input(prompt)) return value except ValueError: print("Vui lòng nhập một số hợp lệ!")
age = get_number("Nhập tuổi: ")print(f"Tuổi của bạn: {age}")Ví dụ 2: Đọc file an toàn
Phần tiêu đề “Ví dụ 2: Đọc file an toàn”def read_file_safe(filename): try: with open(filename, 'r') as file: content = file.read() return content except FileNotFoundError: print(f"File '{filename}' không tồn tại!") return None except PermissionError: print(f"Không có quyền đọc file '{filename}'!") return None except Exception as e: print(f"Lỗi không xác định: {e}") return None
content = read_file_safe("data.txt")if content: print(content)Ví dụ 3: Truy cập dictionary an toàn
Phần tiêu đề “Ví dụ 3: Truy cập dictionary an toàn”def get_student_score(students, name): try: return students[name] except KeyError: return f"Học sinh '{name}' không tồn tại"
students = {"Alice": 95, "Bob": 87}print(get_student_score(students, "Alice")) # 95print(get_student_score(students, "Charlie")) # "Học sinh 'Charlie' không tồn tại"Ví dụ 4: Calculator với error handling
Phần tiêu đề “Ví dụ 4: Calculator với error handling”def calculator(): while True: try: operation = input("Nhập phép tính (hoặc 'quit'): ") if operation.lower() == 'quit': break
result = eval(operation) print(f"= {result}") except ZeroDivisionError: print("Lỗi: Không thể chia cho 0!") except SyntaxError: print("Lỗi: Cú pháp không đúng!") except NameError: print("Lỗi: Biến không tồn tại!") except Exception as e: print(f"Lỗi: {e}")
calculator()Ví dụ 5: Retry mechanism
Phần tiêu đề “Ví dụ 5: Retry mechanism”def connect_to_server(max_retries=3): for attempt in range(max_retries): try: print(f"Thử kết nối lần {attempt + 1}...") # Giả lập kết nối import random if random.random() > 0.5: raise ConnectionError("Kết nối thất bại")
print("Kết nối thành công!") return True except ConnectionError as e: print(f"Lỗi: {e}") if attempt == max_retries - 1: print("Hết số lần thử!") return False
return False
connect_to_server()11. Best Practices
Phần tiêu đề “11. Best Practices”1. Bắt exception cụ thể
Phần tiêu đề “1. Bắt exception cụ thể”# TỐTtry: number = int(input("Nhập số: "))except ValueError: print("Số không hợp lệ")
# TRÁNHtry: number = int(input("Nhập số: "))except: print("Có lỗi")2. Không bắt exception quá rộng
Phần tiêu đề “2. Không bắt exception quá rộng”# TỐTtry: result = risky_operation()except (ValueError, TypeError) as e: handle_error(e)
# TRÁNHtry: result = risky_operation()except Exception: pass # Nuốt tất cả lỗi - rất nguy hiểm!3. Log lỗi
Phần tiêu đề “3. Log lỗi”try: process_data()except Exception as e: print(f"Lỗi: {e}") # Ghi log để debug sau with open("error.log", "a") as log: log.write(f"{datetime.now()}: {e}\n")4. Cleanup với finally
Phần tiêu đề “4. Cleanup với finally”file = Nonetry: file = open("data.txt", "r") process(file)except FileNotFoundError: print("File không tồn tại")finally: if file: file.close()5. Fail fast
Phần tiêu đề “5. Fail fast”def process_user(user_id): if not user_id: raise ValueError("user_id không thể rỗng")
# Tiếp tục xử lý...12. Context Manager (with statement)
Phần tiêu đề “12. Context Manager (with statement)”Cách tốt nhất để xử lý tài nguyên (file, connection):
# Tự động close filetry: with open("data.txt", "r") as file: content = file.read() print(content)except FileNotFoundError: print("File không tồn tại")# File tự động được đóng, ngay cả khi có lỗiBài giảng trên YouTube
Phần tiêu đề “Bài giảng trên YouTube”📝 Bài tập thực hành
Phần tiêu đề “📝 Bài tập thực hành”Sau khi học xong bài này, hãy thực hành với các bài tập sau: