Vietnamese (Tiếng Việt) translation by Vũ Thanh Hải (you can also view the original English article)
Khi nhắc đến gỡ lỗi nghĩa là có thể có một lỗi ở giữa. Vâng, ý tôi không phải là một con gián một có thể tìm thấy trong một ngôi nhà—điều tôi nói ở đây là đây là một lỗi lập trình!
Trước tiến sâu hơn với hướng dẫn này, chúng ta phải hiểu được một số thuật ngữ. Chúng ta hãy dùng một thời gian ngắn định nghĩa một lỗi và gỡ lỗi là gì.
Lỗi
Một lỗi trong điện toán đám mây xảy ra cả ở trong phần mềm và phần cứng, nhưng điều chúng ta tập trung ở đây là lỗi phần mềm. Hãy để tôi nhanh chóng đề cập đến một điều là thuật ngữ lỗi có có nguồn gốc từ đâu. Người ta tin rằng thuật ngữ lỗi xuất hiện đầu tiên trong tính toán là khi một con gián thật (bug) được tìm thấy ở một relay của máy tính Mark II. Thuật ngữ bug cũng từng được sử dụng cuối thế kỉ 19 để mô tả lỗi kĩ thuật.
Bug trong phần mềm làm cho chương trình tạo ra hành động ngoài ý muốn. Nó là một thuật ngữ được sử dụng phổ biến để nhắc đến một lỗi không biết vị trí và nguyên nhân, và có để gây ra nhiều vấn đề (vd: crash phần mềm)
Trong tình huống này, debug xuất hiện.
Debug
Vâng, người ta có thể nói cách tốt nhất để tránh rắc rối là đừng gây ra lỗi từ đầu. Nhưng điều này hiếm có, và không dễ để tạo ra chương trình sạch sẽ từ đầu. Có lỗi là điều bình thường.
Debug là quá trình xác định, phân tích và sửa lỗi xảy ra. Mục tiêu cuối cùng của việc debug là xóa lỗi và tạo ra phần mềm hoạt động như ý muốn. Phần lớn thời gian là để xác định lỗi như nói ở trên, chúng ta không biết nó từ đâu ra.
Để biết được việc debug khó thế nào, hãy xem những gì Brian W. Kernighan nói:
Mọi người đều biết debug khó gấp đôi viết phần mềm. Vậy nếu bạn thông minh như lúc bạn viết nó, bạn sẽ debug kiểu gì?
Xử lí Exception trong Python
Một exception là một đối tượng chỉ ra rằng ta có một lỗi. Nói cách khác, Python sử dụng exception để nói rằng có lỗi trong phần mềm. Đây sẽ là phần xác định lỗi trong quá trình debug. Nhận một đối tượng exception và thực hiện việc xử lí lỗi là xử lí exception. Nó sẽ là bước phân tích và sửa trong việc debug.
Hàm try
Hàm try
của Python dùng để chỉ việc xử lí exception và có hai dạng: try/except
và try/finally
. Trong trường hợp đầu, hàm try
có thể đi theo except
sau nó, còn trong trường hợp khác, nó chỉ được kèm theo sau một hàm finally
.
try/except
Cú pháp try/except
là như sau:
1 |
try: |
2 |
# try block code
|
3 |
except: |
4 |
# except block code
|
Phần thân try
sẽ gồm code có thể tạo ra exception, nếu một exception được tạo ra, tất cả câu lệnh trong block sẽ bị bỏ qua. Mặt khác,phần thân của except
được gọi bởi exception handler, vì nó được dùng để bắt lỗi. Block except sẽ thực hiện khi lỗi được tạo ra, không thì block sẽ được bỏ qua. Bạn có thể dùng exception có sẵn trong Thư viện chuẩn Python.
Hãy xem một ví dụ để hiểu rõ hơn. Chúng ta đã được yêu cầu nhập mẫu số một trong một công thức phân chia. Vì không thể chia cho số không, hãy viết lệnh try/except
để kiểm tra xem có lệnh chia cho không và thông báo lỗi nếu có.
1 |
denominator = input('Enter a denominator value: ') |
2 |
try: |
3 |
formula = 15/denominator |
4 |
print 'The result is ' + str(formula) |
5 |
except ZeroDivisionError: |
6 |
print 'You attempted to divide by zero which is not allowed' |
Nếu bạn nhập số 5
, bạn sẽ nhận được kết quả sau:
1 |
The result is 3 |
Bây giờ hãy thử nhập số 0. Trường hợp này bạn sẽ nhận kết quả gì?
try/finally
try/finally
là một cách khác để viết lệnh try trong Python. finally
được gọi là làm-sạch/chấm dứt vì nó luôn luôn có thể chạy bất kể cho dù một lỗi xảy ra trong block try
.
Hãy thử ví dụ trên với hàm finally
:
1 |
denominator = input('Enter a denominator value: ') |
2 |
try: |
3 |
formula = 15/denominator |
4 |
print 'The result is ' + str(formula) |
5 |
finally: |
6 |
print 'You attempted to divide by zero which is not allowed' |
Hãy để ý khi bạn nhập 5
bạn sẽ được kết quả:
1 |
The result is 3 |
2 |
You attempted to divide by zero which is not allowed |
Từ khóa raise
Từ khóa raise
là một cách khác để xử lí exception trong Python. Trong trường hợp này, bạn sẽ có thể tạo nên exception của riêng bạn-đó là exception được nêu ra khi một vấn đề bên ngoài phạm vi của dự kiến lỗi xảy ra.
Hãy xem ví dụ sử dụng từ khóa raise
để hiểu rõ hơn.
1 |
try: |
2 |
x = input('Enter a number in the range 1-10: ') |
3 |
if x<1 or x>10: |
4 |
raise Exception |
5 |
print 'Great! You listened to me and entered a valid number' |
6 |
|
7 |
except: |
8 |
print 'Your number seems to be outside the range 1-10' |
Trong ví dụ này, nếu bạn nhập một số bên ngoài các phạm vi cho phép, các lệnh print
trong các except
block sẽ được thực hiện.
Hãy thử một số giá trị và xem kết quả.
Module traceback
module traceback
là cách khác để xử lí exception trong Python. Nó về cơ bản được sử dụng để print dấu vết của một chương trình sau khi một exception xảy ra. traceback
bao gồm thông báo lỗi, số dòng gây ra lỗi và call stack của function gây ra lỗi.
Hãy lấy một ví dụ tạo ra traceback
:
1 |
def createException(name): |
2 |
raise Exception('It seems that ' + name + ' raised an exception') |
3 |
|
4 |
createException('Abder') |
Nếu bạn chạy đoạn script này, bạn sẽ nhận được:
1 |
Traceback (most recent call last): |
2 |
File "test.py", line 4, in <module> |
3 |
createException('Abder') |
4 |
File "test.py", line 2, in createException |
5 |
raise Exception('It seems that ' + name + ' raised an exception') |
6 |
Exception: It seems that Abder raised an exception |
Chú ý đến bug (lỗi) xảy ra ở dòng 2
trong function createException
. Chú ý rằng call stack sẽ giúp theo dõi xem lỗi từ đâu ra, trong trường hợp này là dòng 4
.
Bài hướng dẫn đang dài ra, và tôi muốn dừng tại đây. Như bạn thấy, debug chương trình là một điều tự nhiên, và tôi tin rằng kiểu lỗi này bạn đã thường gặp, phải không?
Có nhiều cách khác để debug chương trình Python và xử lí nó. Một cách phổ biến là assert statement
.
Chúc bạn vá lỗi vui vẻ!