Ngôn ngữ Python
Exception Handling (Try/Except)

Exception Handling (Try/Except)

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

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

# 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ạy
try:
    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

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ể

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

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ụ

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

ExceptionKhi nào xảy raVí dụ
ValueErrorGiá trị không đúng kiểuint("abc")
ZeroDivisionErrorChia cho 010 / 0
TypeErrorSai kiểu dữ liệu"hello" + 5
IndexErrorIndex vượt quá phạm vi[1,2,3][10]
KeyErrorKey không tồn tạidict["key"]
FileNotFoundErrorFile không tồn tạiopen("xyz.txt")
AttributeErrorThuộc tính không tồn tại"hello".xyz()
NameErrorBiến chưa được định nghĩaprint(x)

Ví dụ từng loại

# ValueError
try:
    number = int("abc")
except ValueError as e:
    print(f"ValueError: {e}")
 
# IndexError
try:
    my_list = [1, 2, 3]
    print(my_list[10])
except IndexError as e:
    print(f"IndexError: {e}")
 
# KeyError
try:
    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'

try:
    result = 10 / 0
except ZeroDivisionError as error:
    print(f"Lỗi: {error}")
    print(f"Loại lỗi: {type(error).__name__}")

Kết quả:

Lỗi: division by zero
Loại lỗi: ZeroDivisionError

6. Bắt nhiều Exception

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

try:
    # Code
    pass
except (ValueError, TypeError, ZeroDivisionError) as e:
    print(f"Lỗi: {e}")

6.3 - Bắt tất cả Exception (không khuyến khích)

try:
    # Code
    pass
except Exception as e:
    print(f"Có lỗi: {e}")

7. Else và Finally

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

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:
        pass

7.3 - Cấu trúc đầy đủ

try:
    # Code có thể gây lỗi
    result = 10 / 2
except 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

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

try:
    result = 10 / 0
except ZeroDivisionError:
    print("Ghi log lỗi...")
    raise  # Ném lại exception để xử lý ở nơi khác

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ế

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

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

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"))   # 95
print(get_student_score(students, "Charlie")) # "Học sinh 'Charlie' không tồn tại"

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

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

1. Bắt exception cụ thể

# TỐT
try:
    number = int(input("Nhập số: "))
except ValueError:
    print("Số không hợp lệ")
 
# TRÁNH
try:
    number = int(input("Nhập số: "))
except:
    print("Có lỗi")

2. Không bắt exception quá rộng

# TỐT
try:
    result = risky_operation()
except (ValueError, TypeError) as e:
    handle_error(e)
 
# TRÁNH
try:
    result = risky_operation()
except Exception:
    pass  # Nuốt tất cả lỗi - rất nguy hiểm!

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

file = None
try:
    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

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)

Cách tốt nhất để xử lý tài nguyên (file, connection):

# Tự động close file
try:
    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ỗi

Bài giảng trên YouTube

Cập nhật sau


Lập trình Python - Bumbii Academy