Từ Khóa Else Trong Python - 3 Điều Có Thể Bạn Chưa Biết?

Từ Khóa Else Trong Python - 3 Điều Có Thể Bạn Chưa Biết?

Bạn có chắc mình đã hiểu hết về cách dùng & ngữ cảnh sử dụng từ khóa else trong Python? Khi nào thì có else xuất hiện trong câu lệnh Python?
Thường thì câu trả lời sẽ là: "Có if thì sẽ có else". Bài viết này của tôi sẽ nói về cách từ khóa else xuất hiện mà không đi kèm với if. Tất nhiên là vẫn giữ nguyên như ý nghĩa của từ else, cũng là rẽ nhánh khi không thỏa mãn điều kiện nào đó.

0. If...else...

Bất kỳ ai có kinh nghiệm lập trình đều nên quen thuộc với câu lệnh if… else ở định dạng

if condition_1:
    do_action_1
else:
    do_action_2

if...else... tạo ra một nhánh logic bằng cách kiểm tra một điều kiện condition_1, nếu điều kiện thỏa mãn (condition_1 == True) thì thực hiện do_action_1, nếu không thỏa mãn (condition_1 == False) thì thực hiện do_action_2. Do là điều kiện trái ngược nhau nên chỉ 1 trong 2 action được thực hiện.

Ví dụ:

import random

number = random.randint(0, 100)

if number % 2 == 0:
    print("{} is even number".format(number))
else:
    print("{} is even odd".format(number))

90 is even number

Một số ngôn ngữ lập trình ngoài if... else... thì có thêm cú pháp switch...case...
Ở Python không có switch...case... nhưng nếu có nhiều điều kiện rẽ nhánh, Python cung cấp thêm một từ khóa elif để thực hiện so sánh điều kiện phụ phía dưới.

Ví dụ: cho bài toán FIZZBUZZ trong khoảng từ 1--> 20:

for number in range(1, 21):
    if number % 3 == 0 and number % 5 == 0:
        print("FIZZBUZZ")
    elif number % 3 == 0:
        print("FIZZ")
    elif number % 5 == 0:
        print("BUZZ")
    else:
        print(number)

1
2
FIZZ
4
BUZZ
FIZZ
7
8
FIZZ
BUZZ
11
FIZZ
13
14
FIZZBUZZ
16
17
FIZZ
19
BUZZ

Trong hầu hết các ngôn ngữ , mệnh đề else chỉ tồn tại trong câu lệnh if… else... và chúng không xuất hiện ở bất kỳ ngữ cảnh nào khác. Tuy nhiên, ở Python không chỉ "tầm thường" như thế. Python có nhiều hơn 01 cách sử dụng mệnh đề else. Các cách đó là gì, mời các bạn tiếp tục đọc bài viết & một số ví dụ để hiểu rõ vấn đề.

1. Sử dụng else với for

Chúng ta đều biết for thường được dùng để duyệt qua từng phần tử trong một danh sách hoặc tạo ra một vòng lặp có giới hạn. Chúng ta thường gặp cách sử dụng vòng lặp for ở format như bên dưới.

Ví dụ: Cho một danh sách stored_items chứa các món hàng đang còn trong kho hàng, danh sách order_items chứa các mặt hàng được đặt hàng. Thực hiện kiểm tra, nếu stored_items chứa tất cả các phần tử của order_items thì in ra màn hình "accpected order", nếu không in ra màn hình "rejected order"

stored_items = ['coca-cola', 'pepsi', 'lavie', 'vodka', 'beer', 'bean', 'meat']
order_items = ['pepsi', 'vodka', 'beer']

is_avaiable = True
for item in order_items:
    if item not in stored_items:
        print("reject order! Because {} isn't avaiable".format(item))
        is_avaiable = False
        break
if is_avaiable:
    print("accpected order")

Với dữ liệu order_items như trên thì kết quả sẽ in ra:

accpected order

Thay đổi dữ liệu order_items = ['pepsi', 'vodka', 'beer', 'cookie']

Kết quả sẽ in ra:
reject order! Because cookie isn't avaiable

Vậy else sẽ xuất hiện ở đâu trong ngữ cảnh trên và việc có else sẽ giải quyết được vấn đề gì ?

Theo như định nghĩa từ trang doc của Python (https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops) thì else đi cùng với for sẽ thực hiện các câu lệnh đằng sau nó nếu như không có sự kiện break được thực thi để thoát khỏi vòng lặp for.

Áp dụng vào ví dụ trên, chúng ta có thể giảm bớt việc đặt một biến is_avaiable và câu lệnh so sánh với nó.

Như hình trên thì tại cụm dữ liệu thứ 1, câu lệnh break tại dòng số 5 không được thực thi nên câu lệnh print (dòng 7) ở block lệnh phía sau từ khóa else được thực hiện. Kết quả in ra "accpected order"

Hình bên dưới, câu lệnh break được thực thi nên câu lệnh print ở dòng số 7 không còn được thực thi.

2. Sử dụng else với while

Câu lệnh while xây dựng ra một vòng lặp khá hữu ích khi các nhân tố so sánh trong điều kiện để tiếp tục vòng lặp có thể được tính toán lại ngay trong block lệnh phía dưới.

Ví dụ: Khách hàng có một tài khoản tiết kiệm có số dư là saving_balance = 1000, mỗi lần khách hàng sẽ rút cố định withdraw_money = 200.
Yêu cầu:
- In ra màn hình số tiền khách hàng rút ra và số tiền còn lại trong tài khoản: "Withdraw {withdraw_money}, and remains: {saving_balance}"
- Nếu tài khoản của khách hàng còn lại nhỏ hơn alert_money thì in ra màn hình: "Balance is less than {alert_money}, please stop withdraw!". Ngừng không cho khách hàng rút tiền nữa
- Nếu tài khoản của khách hàng lại nhỏ hơn hoặc bằng 0 thì ngừng thực hiện cho phép rút tiền và in ra màn hình: "Not enough money in the saving account"

Thông thường thì chúng ta sẻ giải quyết bài toán bằng cách như sau:

def check_withdraw_money(alert_money):
    print("alert_money: ", alert_money)
    saving_balance = 1000
    while saving_balance > 0:
        if saving_balance < alert_money:
            print("Balance is less than {alert_money}, please stop withdraw!".format(alert_money=alert_money))
            break
        saving_balance -= 200
        print("Withdraw 200, and remains: {saving_balance}".format(saving_balance=saving_balance))
    if saving_balance < 0:
        print("Not enough money in the saving account")

Với dữ liệu alert_money = 100 và alert_money = 350, chúng ta gọi vào function trên và nhận được kết quả:

Ngữ cảnh sử dụng else đi kèm với câu lệnh while cũng tương tự for ở trên. Các lệnh đứng sau else sẽ được thực hiện nếu lòng lặp được tạo bởi while không bị ngắt bởi sự kiện được sinh ra của từ khóa break.

Với bài toán trên, cách làm tôi đưa ra cũng "tạm" đáp ứng được yêu cầu của đề bài. Nhưng nếu chúng ta đưa từ khóa else vào sử dụng, chúng ta sẽ "tiết kiệm" được một phép so sánh saving_balance < 0

Kết quả của function với alert_money = 100 và 350:

Như ví dụ trên: Với alert_money = 100 thì người dùng có thể rút được số tiền về đến giá trị = 0 (1000 = 200 * 5) nên câu lệnh break tại dòng 7 không được thực hiện. Vòng lặp while kết thúc một cách bình thường và dòng "Not enough money in the saving account" được in ra màn hình.
Với alert_money = 350, thì sau lần rút tiền thứ 4, người dùng còn saving_balance = 200, giá trị này nhỏ hơn 350 nên sẽ in ra dòng số 6 "Balance is less than 350, please stop withdraw!" và thực hiện lệnh break tại dòng số 7. Do vòng lặp bị ngắt đột ngột nên câu lệnh sau else sẽ không được thực hiện.

3. Sử dụng else với try

Xử lý ngoại lệ (exception)là một công việc phức tạp trong lập trình không chỉ với ngôn ngữ lập trình Python mà cả các ngôn ngữ lập trình khác nữa.
Nếu bạn không thực hiện việc "bắt ngoại lệ," chương trình của bạn có thể sẽ bị "văng" ra bất cứ lúc nào nếu có lỗi nào đó xảy ra.
Nếu bạn thực hiện quá chặt chẽ thì hiệu năng của chương trình lại bị suy giảm khá nhiều. Trong bài viết này, tôi sẽ không thực hiện giới thiệu với các bạn về try...except trong Python (sẽ giới thiệu ở bài viết khác), mà sẽ nói đến việc sử dụng try...else... để xử lý một số trường hợp ngoại lệ trong python.

Ví dụ: Cho một danh sách chứa các ký tự, thực hiện convert các ký tự trong danh sách sang dạng số, nếu convert thành công toàn bộ in ra màn hình tổng các số trong danh sách. Nếu convert không thành công, in ra màn hình "Can't cast value to a number"

Thông thường, chúng ta sẽ viết như này:

def sum_of_cast_number(number_chars):
    total = 0
    try:
        for number_char in number_chars:
            total += int(number_char)
    except ValueError:
        total = 0
        print("Can't cast value to a number")

    if total > 0:
        print("Sum of numbers: ", total)

Với những dữ liệu đầu vào, chúng ta sẽ thu được kết quả:

Ngữ cảnh sử dụng else với try như sau: Nếu trong quá trình thực thi lệnh, chương trình không bị "nhảy" vào phần "bẫy" ngoại lệ thì các câu lệnh trong block lệnh đứng ở level sau từ khóa else sẽ được thực hiện.

Ta sẽ xây dựng function v2 với try...else...

Với cách sử dụng else trong try ... except... như ở ví dụ trên, giúp chúng ta tiết kiệm được 1 dòng lệnh gán dữ liệu total = 0 và câu lệnh so sánh total > 0.
Khi không có trường hợp nào bị rơi vào "bẫy" ValueError ở dòng số 6, dòng lệnh in ra màn hình tại dòng 9 sẽ được thực thi.
Trường hợp có lỗi ValueError xảy ra thì dòng lệnh số 7 được thực thi.

Tổng kết:

Bài viết trên, tôi đã đưa ra 03 trường hợp sử dụng từ khóa else trong các ngữ cảnh có kết hợp với các từ khóa for, while, try. Có lẽ sẽ hơi khó hiểu cho các bạn mới lần đầu nhìn thấy các trường hợp này. Mặc dù việc sử dụng "nâng cao" từ khóa else mang lại nhiều lợi ích cho performance của chương trình nhưng nó sẽ là trở ngại với những người chuyển từ ngôn ngữ lập trình khác sang khi sẽ phải cố hiểu xem tại sao lại dùng else. Vì vậy việc sử dụng hay không sử dụng tùy thuộc vào "quy ước" lập trình chung trong team của bạn để các thành viên có thể hỗ trợ tốt cho nhau.
Chúc các bạn sau khi đọc bài viết này xong sẽ không bị bỡ ngỡ và giật mình khi thấy tự nhiên phía sau for, while, try lại có else.
Cảm ơn các bạn đã đọc bài viết.