Ngay cả những lập trình viên dày dạn nhất cũng mắc lỗi khi viết mã. Với lập trình viên Python, các lỗi này thường rơi vào hai nhóm: lỗi (error) hoặc ngoại lệ (exception).
Lỗi chủ yếu liên quan đến cú pháp và phải được sửa thì chương trình mới chạy. Ngoại lệ, ngược lại, xảy ra khi mã đúng về mặt cú pháp nhưng có điều gì đó làm gián đoạn chương trình khi đang chạy.
Trong hướng dẫn này, chúng ta sẽ xem xét một trong những ngoại lệ phổ biến nhất mà cả người mới lẫn người có kinh nghiệm thường gặp: ngoại lệ KeyError. Chúng ta sẽ đi vào chi tiết về KeyError của Python, kèm ví dụ và các kỹ thuật khác nhau để xử lý kiểu ngoại lệ này. Nếu bạn muốn học cách nhận diện và sửa lỗi trong Python, hãy xem thêm hướng dẫn Xử lý ngoại lệ & lỗi trong Python.
Ngoại lệ KeyError là gì?
Trong Python, ngoại lệ KeyError là một trong các ngoại lệ dựng sẵn được thiết kế để xử lý nhiều tình huống lỗi phổ biến. Có thể hiểu KeyError là một lớp con, cùng với IndexError, của ngoại lệ tổng quát hơn là LookupError; tất cả đều là đối tượng của lớp Exception.
Cụ thể, KeyError được ném ra khi lập trình viên cố truy cập một khóa không tồn tại trong từ điển (dictionary). Từ điển, để tham chiếu, là cấu trúc dữ liệu lưu trữ dữ liệu theo cặp khóa–giá trị, và giá trị được truy cập thông qua khóa — vì vậy mới có tên KeyError.
Nguyên nhân thường gặp và ví dụ về KeyError trong Python
Hãy xem một ví dụ với một từ điển chứa các quốc gia và thủ đô của chúng:
dictionary_capitals ={'Madrid':'Spain','Lisboa':'Portugal','London':'United Kingdom'}Được hỗ trợ bởi
Để tra cứu thông tin trong từ điển, chúng ta cần chỉ định khóa trong dấu ngoặc vuông và Python sẽ trả về giá trị tương ứng.
Traceback (most recent call last):
File "<stdin>", line 1,in<module>
KeyError:'Rome'Được hỗ trợ bởi
Chúng ta cũng có thể gặp ngoại lệ KeyError khi cố truy cập các khóa không tồn tại trong những đối tượng ánh xạ (mapping) khác của Python có dạng như một từ điển. Ví dụ, đối tượng os.environ trả về một từ điển lưu các biến môi trường của người dùng làm khóa kèm giá trị tương ứng.
Trong đoạn mã sau, chúng ta thử truy cập giá trị gắn với khóa USERS trong từ điển os.environ. Vì USERS không có trong os.environ, mã của chúng ta sinh ra KeyError.
#Calling a non-existent environmental variable
os.environ['USERS']
Traceback (most recent call last):
File "<stdin>", line 1,in<module>
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/os.py", line 679,in __getitem__
raise KeyError(key)fromNone
KeyError:'USERS'Được hỗ trợ bởi
Hãy cùng khám phá các phương pháp xử lý KeyError. Có hai chiến lược: hoặc phòng ngừa KeyError, hoặc bắt KeyError bằng cơ chế xử lý lỗi.
Phòng ngừa KeyError
Như đã thấy, Python sẽ ném KeyError nếu chúng ta cố truy cập một khóa không tồn tại. Để ngăn điều này, ta có thể truy cập khóa trong từ điển bằng phương thức .get() để mã khoan dung hơn. Khi dùng phương thức này, nếu gặp khóa không tồn tại, Python sẽ trả về giá trị None thay vì KeyError. Đây là một cách tiếp cận tốt.
Ngoài ra, chúng ta có thể kiểm tra khóa có tồn tại hay không trước khi truy cập. Cách phòng ngừa ngoại lệ này được gọi là “Nhìn trước khi nhảy” (Look Before You Leap — LBYL). Trong trường hợp này, ta có thể dùng câu lệnh if để kiểm tra sự tồn tại của khóa và nếu không có, ta xử lý trong mệnh đề else.
capital ="Prague"if capital in dictionary_capitals.keys():
value = dictionary_capitals[capital]else:print("The key {} is not present in the dictionary".format(capital))Được hỗ trợ bởi
Bắt KeyError bằng xử lý ngoại lệ
Cách tiếp cận thứ hai được gọi là “Xin tha thứ dễ hơn xin phép” (Easier to Ask Forgiveness Than Permission — EAFP) và thực ra là cách chuẩn hơn để xử lý ngoại lệ trong Python.
Theo phong cách EAFP, ta giả định các khóa hợp lệ tồn tại và bắt ngoại lệ nếu giả định đó sai. Trong khi LBYL dựa vào các câu lệnh if/else, EAFP dựa vào các khối try/except.
Trong ví dụ sau, thay vì kiểm tra khóa có tồn tại, ta thử truy cập khóa mong muốn. Nếu vì lý do nào đó khóa không có, ta chỉ cần bắt KeyError trong khối except và xử lý phù hợp.
capital ="Prague"try:
value = dictionary_capitals[capital]except KeyError:print("The key {} is not present in the dictionary".format(capital))Được hỗ trợ bởi
Quản lý KeyError nâng cao trong Python
Dùng defaultdict để xử lý khóa tự động
Ta thấy rằng mỗi khi cố truy cập một khóa không có trong từ điển, Python sẽ trả về ngoại lệ KeyError. Phương thức .get() mà ta đã xem là một cách tiếp cận khoan dung với lỗi và hoạt động ổn, nhưng chưa tối ưu.
Mô-đun Collections cung cấp defaultdict, một cách tối ưu hơn để xử lý các mục trong từ điển. Khác với từ điển chuẩn sẽ ném KeyError khi truy cập khóa không tồn tại, defaultdict cho phép ta chỉ định một giá trị mặc định được trả về bất cứ khi nào không tìm thấy khóa. Đoạn mã sau cho thấy cách import defaultdict từ Collections và tạo giá trị mặc định bằng hàm lambda. Nếu bạn còn bối rối về hàm lambda, hãy xem hướng dẫn Python lambda để tìm hiểu thêm.
from collections import defaultdict
# Defining the dict
capitals = defaultdict(lambda:"The key doesn't exist")
capitals['Madrid']='Spain'
capitals['Lisboa']='Portugal'print(capitals['Madrid'])print(capitals['Lisboa'])print(capitals['Ankara'])Được hỗ trợ bởi
Cuối cùng, trong một số trường hợp, việc cố ý ném ra KeyError có thể phù hợp để áp đặt một số ràng buộc nhất định.
Chúng ta biết rằng trong nhiều tình huống, hàm phụ thuộc vào dữ liệu cụ thể để thực thi thao tác. Chủ động kích hoạt KeyError sẽ đảm bảo hàm thất bại một cách rõ ràng và có thể dự đoán khi dữ liệu bắt buộc bị thiếu. Trong những trường hợp này, thông điệp lỗi đi kèm KeyError giúp ta hiểu chính xác vấn đề với đầu vào, từ đó gỡ lỗi dễ hơn.
Hãy làm rõ bằng một ví dụ. Ở đây chúng ta tạo một hàm nhận một từ điển làm đối số. Người dùng phải cung cấp từ điển với các khóa phù hợp để hàm hoạt động chính xác. Chúng ta tạo hàm trong trường hợp này vì muốn biết ngay nếu thiếu khóa, thay vì để lỗi tồn tại sâu hơn trong mã.
defmy_function(my_dict):if'critical_key'notin my_dict:raise KeyError('critical_key is missing from the dictionary. Please modify the dictionary')Được hỗ trợ bởi
Kết luận
Hy vọng bạn thấy bài viết hữu ích. KeyError là một trong những ngoại lệ phổ biến nhất mà lập trình viên Python sẽ gặp. Thành thạo nghệ thuật xử lý lỗi và ngoại lệ là phần then chốt để trở thành một lập trình viên Python vững vàng. Tìm hiểu thêm về các kỹ thuật lập trình hàm và các nền tảng mã hóa khác với các lộ trình kỹ năng Python Programming và Python Fundamentals. Ngoài ra, hãy xem hướng dẫn Tập hợp trong Python và lý thuyết tập hợp để tìm hiểu thêm về các khái niệm liên quan.
Tôi là một chuyên viên phân tích dữ liệu tự do, hợp tác với các công ty và tổ chức trên toàn thế giới trong các dự án khoa học dữ liệu. Tôi cũng là giảng viên khoa học dữ liệu với hơn 2 năm kinh nghiệm. Tôi thường xuyên viết bài về khoa học dữ liệu bằng tiếng Anh và tiếng Tây Ban Nha; một số bài đã được đăng trên các trang uy tín như DataCamp, Towards Data Science và Analytics Vidhya. Là một nhà khoa học dữ liệu có nền tảng khoa học chính trị và luật, mục tiêu của tôi là làm việc tại giao điểm giữa chính sách công, pháp luật và công nghệ, tận dụng sức mạnh của ý tưởng để thúc đẩy các giải pháp và cách tiếp cận mới nhằm giúp chúng ta đối mặt với những thách thức cấp bách, đặc biệt là khủng hoảng khí hậu. Tôi xem mình là người tự học, không ngừng trau dồi và là một người ủng hộ vững chắc cho tính đa ngành. Không bao giờ là quá muộn để học điều mới.
Ngay cả những lập trình viên dày dạn nhất cũng mắc lỗi khi viết mã. Với lập trình viên Python, các lỗi này thường rơi vào hai nhóm: lỗi (error) hoặc ngoại lệ (exception).
Lỗi chủ yếu liên quan đến cú pháp và phải được sửa thì chương trình mới chạy. Ngoại lệ, ngược lại, xảy ra khi mã đúng về mặt cú pháp nhưng có điều gì đó làm gián đoạn chương trình khi đang chạy.
Trong hướng dẫn này, chúng ta sẽ xem xét một trong những ngoại lệ phổ biến nhất mà cả người mới lẫn người có kinh nghiệm thường gặp: ngoại lệ
KeyError. Chúng ta sẽ đi vào chi tiết vềKeyErrorcủa Python, kèm ví dụ và các kỹ thuật khác nhau để xử lý kiểu ngoại lệ này. Nếu bạn muốn học cách nhận diện và sửa lỗi trong Python, hãy xem thêm hướng dẫn Xử lý ngoại lệ & lỗi trong Python.Ngoại lệ KeyError là gì?
Trong Python, ngoại lệ
KeyErrorlà một trong các ngoại lệ dựng sẵn được thiết kế để xử lý nhiều tình huống lỗi phổ biến. Có thể hiểuKeyErrorlà một lớp con, cùng vớiIndexError, của ngoại lệ tổng quát hơn làLookupError; tất cả đều là đối tượng của lớpException.Cụ thể,
KeyErrorđược ném ra khi lập trình viên cố truy cập một khóa không tồn tại trong từ điển (dictionary). Từ điển, để tham chiếu, là cấu trúc dữ liệu lưu trữ dữ liệu theo cặp khóa–giá trị, và giá trị được truy cập thông qua khóa — vì vậy mới có tênKeyError.Nguyên nhân thường gặp và ví dụ về KeyError trong Python
Hãy xem một ví dụ với một từ điển chứa các quốc gia và thủ đô của chúng:
Để tra cứu thông tin trong từ điển, chúng ta cần chỉ định khóa trong dấu ngoặc vuông và Python sẽ trả về giá trị tương ứng.
Nếu chúng ta cố truy cập một khóa không có trong từ điển, Python sẽ đưa ra thông báo lỗi ngoại lệ
KeyError.Chúng ta cũng có thể gặp ngoại lệ
KeyErrorkhi cố truy cập các khóa không tồn tại trong những đối tượng ánh xạ (mapping) khác của Python có dạng như một từ điển. Ví dụ, đối tượngos.environtrả về một từ điển lưu các biến môi trường của người dùng làm khóa kèm giá trị tương ứng.Trong đoạn mã sau, chúng ta thử truy cập giá trị gắn với khóa
USERStrong từ điểnos.environ. VìUSERSkhông có trongos.environ, mã của chúng ta sinh raKeyError.Hóa ra, từ điển rất phổ biến trong Python. Một ví dụ khác là cách triển khai một khái niệm trừu tượng hơn gọi là hashmap. Hãy xem hướng dẫn Cẩm nang về Hashmap trong Python để tìm hiểu thêm.
Xử lý ngoại lệ KeyError trong Python
Hãy cùng khám phá các phương pháp xử lý
KeyError. Có hai chiến lược: hoặc phòng ngừaKeyError, hoặc bắtKeyErrorbằng cơ chế xử lý lỗi.Phòng ngừa KeyError
Như đã thấy, Python sẽ ném
KeyErrornếu chúng ta cố truy cập một khóa không tồn tại. Để ngăn điều này, ta có thể truy cập khóa trong từ điển bằng phương thức.get()để mã khoan dung hơn. Khi dùng phương thức này, nếu gặp khóa không tồn tại, Python sẽ trả về giá trịNonethay vìKeyError. Đây là một cách tiếp cận tốt.Ngoài ra, chúng ta có thể kiểm tra khóa có tồn tại hay không trước khi truy cập. Cách phòng ngừa ngoại lệ này được gọi là “Nhìn trước khi nhảy” (Look Before You Leap — LBYL). Trong trường hợp này, ta có thể dùng câu lệnh
ifđể kiểm tra sự tồn tại của khóa và nếu không có, ta xử lý trong mệnh đềelse.Bắt KeyError bằng xử lý ngoại lệ
Cách tiếp cận thứ hai được gọi là “Xin tha thứ dễ hơn xin phép” (Easier to Ask Forgiveness Than Permission — EAFP) và thực ra là cách chuẩn hơn để xử lý ngoại lệ trong Python.
Theo phong cách EAFP, ta giả định các khóa hợp lệ tồn tại và bắt ngoại lệ nếu giả định đó sai. Trong khi LBYL dựa vào các câu lệnh if/else, EAFP dựa vào các khối try/except.
Trong ví dụ sau, thay vì kiểm tra khóa có tồn tại, ta thử truy cập khóa mong muốn. Nếu vì lý do nào đó khóa không có, ta chỉ cần bắt
KeyErrortrong khối except và xử lý phù hợp.Quản lý KeyError nâng cao trong Python
Dùng defaultdict để xử lý khóa tự động
Ta thấy rằng mỗi khi cố truy cập một khóa không có trong từ điển, Python sẽ trả về ngoại lệ
KeyError. Phương thức.get()mà ta đã xem là một cách tiếp cận khoan dung với lỗi và hoạt động ổn, nhưng chưa tối ưu.Mô-đun
Collectionscung cấpdefaultdict, một cách tối ưu hơn để xử lý các mục trong từ điển. Khác với từ điển chuẩn sẽ némKeyErrorkhi truy cập khóa không tồn tại,defaultdictcho phép ta chỉ định một giá trị mặc định được trả về bất cứ khi nào không tìm thấy khóa. Đoạn mã sau cho thấy cách importdefaultdicttừCollectionsvà tạo giá trị mặc định bằng hàmlambda. Nếu bạn còn bối rối về hàm lambda, hãy xem hướng dẫn Python lambda để tìm hiểu thêm.Cố ý tạo ra KeyError
Cuối cùng, trong một số trường hợp, việc cố ý ném ra
KeyErrorcó thể phù hợp để áp đặt một số ràng buộc nhất định.Chúng ta biết rằng trong nhiều tình huống, hàm phụ thuộc vào dữ liệu cụ thể để thực thi thao tác. Chủ động kích hoạt
KeyErrorsẽ đảm bảo hàm thất bại một cách rõ ràng và có thể dự đoán khi dữ liệu bắt buộc bị thiếu. Trong những trường hợp này, thông điệp lỗi đi kèmKeyErrorgiúp ta hiểu chính xác vấn đề với đầu vào, từ đó gỡ lỗi dễ hơn.Hãy làm rõ bằng một ví dụ. Ở đây chúng ta tạo một hàm nhận một từ điển làm đối số. Người dùng phải cung cấp từ điển với các khóa phù hợp để hàm hoạt động chính xác. Chúng ta tạo hàm trong trường hợp này vì muốn biết ngay nếu thiếu khóa, thay vì để lỗi tồn tại sâu hơn trong mã.
Kết luận
Hy vọng bạn thấy bài viết hữu ích.
KeyErrorlà một trong những ngoại lệ phổ biến nhất mà lập trình viên Python sẽ gặp. Thành thạo nghệ thuật xử lý lỗi và ngoại lệ là phần then chốt để trở thành một lập trình viên Python vững vàng. Tìm hiểu thêm về các kỹ thuật lập trình hàm và các nền tảng mã hóa khác với các lộ trình kỹ năng Python Programming và Python Fundamentals. Ngoài ra, hãy xem hướng dẫn Tập hợp trong Python và lý thuyết tập hợp để tìm hiểu thêm về các khái niệm liên quan.