Bài 2.8. Vòng lặp while trong Python

Chào mừng các bạn quay trở lại với series học Python! Trong cuộc sống cũng như trong lập trình, chúng ta thường xuyên phải đối mặt với những công việc cần lặp đi lặp lại. Hãy tưởng tượng bạn phải gửi 100 email giống hệt nhau, chỉ khác tên người nhận. Thay vì sao chép và dán 100 lần, chúng ta cần một cách tự động hóa quy trình đó. Đây chính là lúc các vòng lặp tỏa sáng!

Python cung cấp hai loại vòng lặp chính: forwhile. Trong bài học này, chúng ta sẽ tập trung vào vòng lặp while - một công cụ cực kỳ linh hoạt cho phép bạn thực thi một khối lệnh miễn là một điều kiện nhất định còn đúng.

1. Cú pháp cơ bản của vòng lặp while

Vòng lặp while có cấu trúc khá đơn giản và trực quan:

while dieu_kien:
    # Khối lệnh sẽ được thực thi lặp đi lặp lại
    # Miễn là 'dieu_kien' còn là True
    # ...
    # (Thường có một thao tác cập nhật nào đó ảnh hưởng đến 'dieu_kien')

Giải thích:

  • while: Đây là từ khóa báo hiệu bắt đầu một vòng lặp while.
  • dieu_kien: Đây là một biểu thức logic. Trước mỗi lần lặp, Python sẽ kiểm tra xem biểu thức này có trả về giá trị True hay không.
    • Nếu dieu_kienTrue, khối lệnh bên trong (phần được thụt vào) sẽ được thực thi.
    • Nếu dieu_kienFalse, vòng lặp sẽ kết thúc và chương trình sẽ tiếp tục thực thi các lệnh sau khối while.
  • Khối lệnh: Bao gồm một hoặc nhiều câu lệnh Python được thụt vào cùng một mức so với từ khóa while. Đây là phần công việc sẽ được lặp lại.

Điểm cốt lõi cần nhớ với while: Khối lệnh sẽ chạy không ngừng nếu dieu_kien luôn luônTrue. Do đó, bên trong khối lệnh, bạn phải có một cách nào đó để tác động lên dieu_kien, khiến nó cuối cùng trở thành False để vòng lặp có thể dừng lại. Nếu không, bạn sẽ tạo ra một vòng lặp vô hạn!

2. Ví dụ minh họa vòng lặp while

Hãy cùng xem qua một vài ví dụ để hiểu rõ hơn cách while hoạt động.

Ví dụ 1: Đếm số đơn giản

Đây là ví dụ kinh điển nhất khi bắt đầu với while: đếm từ một số bắt đầu đến một số kết thúc.

# Ví dụ: Đếm từ 1 đến 5 và in ra màn hình
print("Bắt đầu đếm...")
so_dem = 1 # Khởi tạo biến đếm

while so_dem <= 5: # Điều kiện: tiếp tục lặp nếu so_dem còn nhỏ hơn hoặc bằng 5
    print(f"Số hiện tại: {so_dem}")
    so_dem = so_dem + 1 # Quan trọng: Tăng biến đếm lên 1 sau mỗi lần lặp

print("Đã đếm xong!")

Giải thích code:

  1. so_dem = 1: Chúng ta khởi tạo một biến so_dem với giá trị ban đầu là 1.
  2. while so_dem <= 5: Python kiểm tra điều kiện. Lần đầu tiên, 1 <= 5True, nên khối lệnh bên trong được thực thi.
  3. print(f"Số hiện tại: {so_dem}"): In ra giá trị hiện tại của so_dem.
  4. so_dem = so_dem + 1: Đây là bước cập nhật quan trọng. Giá trị của so_dem được tăng lên 1. Nếu không có dòng này, so_dem sẽ mãi mãi là 1, điều kiện so_dem <= 5 luôn đúng, và vòng lặp sẽ chạy vô hạn!
  5. Sau khi tăng so_dem, vòng lặp quay lại bước 2 để kiểm tra lại điều kiện. Quá trình này tiếp tục cho đến khi so_dem tăng lên 6. Lúc này, điều kiện 6 <= 5False, vòng lặp kết thúc.
  6. print("Đã đếm xong!"): Dòng này nằm ngoài vòng lặp và chỉ được thực thi sau khi vòng lặp while đã hoàn thành.

Kết quả:

Bắt đầu đếm...
Số hiện tại: 1
Số hiện tại: 2
Số hiện tại: 3
Số hiện tại: 4
Số hiện tại: 5
Đã đếm xong!
Ví dụ 2: Yêu cầu nhập liệu hợp lệ từ người dùng

Vòng lặp while rất hữu ích khi bạn muốn đảm bảo người dùng nhập vào dữ liệu đúng định dạng hoặc nằm trong một phạm vi cho phép. Vòng lặp sẽ tiếp tục chạy cho đến khi nhận được đầu vào hợp lệ.

# Ví dụ: Yêu cầu người dùng nhập một số nguyên dương
so_nhap = -1 # Khởi tạo giá trị ban đầu không hợp lệ để đảm bảo vòng lặp chạy ít nhất 1 lần

while so_nhap <= 0:
    print("---") # Phân cách các lần nhập
    gia_tri_nhap = input("Vui lòng nhập một số nguyên dương: ")
    try:
        so_nhap = int(gia_tri_nhap) # Thử chuyển đổi sang số nguyên
        if so_nhap <= 0:
            print(f"Lỗi: '{so_nhap}' không phải là số dương. Xin hãy nhập lại.")
    except ValueError:
        print(f"Lỗi: '{gia_tri_nhap}' không phải là một số nguyên hợp lệ. Xin hãy nhập lại.")
        # Giữ so_nhap <= 0 (hoặc giá trị cũ không hợp lệ) để vòng lặp tiếp tục

print(f"Tuyệt vời! Bạn đã nhập số dương: {so_nhap}")

Giải thích code:

  1. so_nhap = -1: Khởi tạo so_nhap với một giá trị chắc chắn làm cho điều kiện so_nhap <= 0True ngay từ đầu.
  2. while so_nhap <= 0: Vòng lặp sẽ tiếp tục chừng nào so_nhap chưa phải là một số dương.
  3. input(...): Nhận đầu vào từ người dùng dưới dạng chuỗi.
  4. try...except ValueError: Chúng ta dùng khối try-except để xử lý trường hợp người dùng nhập vào không phải là số (ví dụ: chữ "abc").
    • try: Thử thực hiện int(gia_tri_nhap). Nếu thành công, gán kết quả cho so_nhap.
    • if so_nhap <= 0: Nếu chuyển đổi thành công nhưng số đó không dương, in thông báo lỗi. Điều kiện while vẫn đúng ở lần kiểm tra tiếp theo.
    • except ValueError: Nếu int() thất bại (người dùng nhập chữ), bắt lỗi ValueError, in thông báo lỗi. Quan trọng là so_nhap không được cập nhật giá trị mới hợp lệ, nên điều kiện while vẫn đúng.
  5. Vòng lặp chỉ kết thúc khi người dùng nhập một chuỗi có thể chuyển đổi thành số nguyên số nguyên đó lớn hơn 0.
Ví dụ 3: Sử dụng giá trị đặc biệt (Sentinel Value) để dừng lặp

Đôi khi, bạn muốn lặp lại một hành động cho đến khi người dùng nhập một giá trị đặc biệt (gọi là sentinel) để báo hiệu kết thúc.

# Ví dụ: Tính tổng các số người dùng nhập, dừng khi nhập số 0
tong = 0
so_hien_tai = None # Khởi tạo khác 0 để vòng lặp bắt đầu

print("Nhập các số bạn muốn tính tổng.")
print("Nhập số 0 để kết thúc và xem kết quả.")

while so_hien_tai != 0: # Điều kiện: tiếp tục nếu số nhập vào chưa phải là 0
    try:
        chuoi_nhap = input("Nhập số (nhập 0 để dừng): ")
        so_hien_tai = int(chuoi_nhap)

        # Chỉ cộng vào tổng nếu số nhập không phải là 0 (số sentinel)
        if so_hien_tai != 0:
             tong = tong + so_hien_tai
        # Nếu so_hien_tai là 0, không cộng, và vòng lặp sẽ dừng ở lần kiểm tra tiếp theo

    except ValueError:
        print("Đó không phải là số hợp lệ. Vui lòng thử lại.")
        # Không cập nhật so_hien_tai, có thể giữ giá trị cũ hoặc để là None
        # để đảm bảo vòng lặp không dừng vì lỗi nhập liệu

# Dòng này chỉ chạy khi vòng lặp kết thúc (khi so_hien_tai == 0)
print(f"Tổng các số bạn đã nhập là: {tong}")

Giải thích code:

  1. tong = 0, so_hien_tai = None: Khởi tạo tổng và biến lưu số hiện tại. Gán None (hoặc bất kỳ giá trị nào khác 0) cho so_hien_tai để đảm bảo điều kiện so_hien_tai != 0True lúc bắt đầu.
  2. while so_hien_tai != 0: Vòng lặp tiếp tục miễn là người dùng chưa nhập số 0.
  3. Bên trong vòng lặp, chương trình yêu cầu nhập số, chuyển đổi sang int (với xử lý lỗi).
  4. if so_hien_tai != 0: tong = tong + so_hien_tai: Chỉ cộng số vào tong nếu nó không phải là giá trị sentinel (số 0).
  5. Khi người dùng nhập 0, so_hien_tai sẽ được gán là 0. Ở lần kiểm tra điều kiện tiếp theo, 0 != 0False, vòng lặp kết thúc.
  6. Cuối cùng, in ra tổng tích lũy được.

3. Lệnh breakelse trong vòng lặp while

Lệnh break

Đôi khi, bạn muốn thoát khỏi vòng lặp while ngay lập tức mà không cần chờ điều kiện trở thành False. Lệnh break cho phép bạn làm điều đó. Khi break được thực thi, vòng lặp sẽ dừng ngay lập tức, và chương trình nhảy đến câu lệnh đầu tiên sau khối while.

# Ví dụ: Tìm số ngẫu nhiên cho đến khi gặp số lớn hơn 90
import random

print("Bắt đầu tìm số may mắn (> 90)...")
so_lan_thu = 0
while True: # Vòng lặp này có vẻ vô hạn?
    so_ngau_nhien = random.randint(1, 100) # Sinh số ngẫu nhiên từ 1 đến 100
    so_lan_thu += 1
    print(f"Lần thử {so_lan_thu}: {so_ngau_nhien}")

    if so_ngau_nhien > 90:
        print(f"Tìm thấy số {so_ngau_nhien} lớn hơn 90!")
        break # Thoát khỏi vòng lặp ngay lập tức!

print(f"Kết thúc sau {so_lan_thu} lần thử.")

Giải thích code:

  • while True: Chúng ta tạo một vòng lặp có điều kiện luôn đúng. Về lý thuyết, nó sẽ chạy mãi mãi.
  • Bên trong, chúng ta sinh số ngẫu nhiên và tăng bộ đếm.
  • if so_ngau_nhien > 90: break: Đây là điều kiện thoát thực sự. Nếu số ngẫu nhiên lớn hơn 90, thông báo được in ra và break được gọi, chấm dứt vòng lặp while True ngay lập tức.
  • Cách dùng while True kết hợp với break rất phổ biến khi điều kiện dừng phức tạp hoặc cần kiểm tra ở giữa vòng lặp.
Mệnh đề else sau while

Đây là một tính năng ít được biết đến hơn của while (và for) trong Python. Khối lệnh trong mệnh đề else sẽ được thực thi chỉ khi vòng lặp kết thúc một cách bình thường (tức là do điều kiện while trở thành False), chứ không phải do lệnh break.

# Ví dụ: Kiểm tra xem một số có phải là số nguyên tố không (cách đơn giản)
num = 13
uoc_so = 2 # Bắt đầu kiểm tra ước từ 2

print(f"Kiểm tra số {num}...")

while uoc_so < num:
    if num % uoc_so == 0:
        print(f"{num} không phải là số nguyên tố (chia hết cho {uoc_so}).")
        break # Tìm thấy ước, không phải số nguyên tố -> thoát lặp
    uoc_so += 1
else:
    # Khối này chỉ chạy nếu vòng lặp while hoàn thành mà không gặp 'break'
    # Điều này có nghĩa là không tìm thấy ước nào từ 2 đến num-1
    if num > 1: # Số nguyên tố phải lớn hơn 1
        print(f"{num} là số nguyên tố!")
    else:
        print(f"{num} không phải là số nguyên tố.")

print("-" * 10)

# Thử với số không nguyên tố
num = 12
uoc_so = 2
print(f"Kiểm tra số {num}...")
while uoc_so < num:
    if num % uoc_so == 0:
        print(f"{num} không phải là số nguyên tố (chia hết cho {uoc_so}).")
        break
    uoc_so += 1
else:
    # Khối này sẽ KHÔNG chạy vì vòng lặp đã bị dừng bởi 'break'
     print(f"{num} là số nguyên tố!")

Giải thích code:

  • Trong trường hợp num = 13, vòng lặp while chạy hết các giá trị của uoc_so từ 2 đến 12. Không có giá trị nào mà 13 % uoc_so == 0, nên break không bao giờ được gọi. Vòng lặp kết thúc bình thường khi uoc_so trở thành 13 (điều kiện uoc_so < numFalse). Do đó, khối else được thực thi, in ra "13 là số nguyên tố!".
  • Trong trường hợp num = 12, khi uoc_so là 2, 12 % 2 == 0True. Lệnh print trong if được thực thi và sau đó break được gọi. Vòng lặp kết thúc do break. Vì vậy, khối else không được thực thi.

4. Cạm bẫy cần tránh: Vòng lặp vô hạn

Như đã đề cập, lỗi phổ biến nhất và nguy hiểm nhất với whilevòng lặp vô hạn. Điều này xảy ra khi điều kiện của vòng lặp while không bao giờ trở thành False.

# Cảnh báo: VÍ DỤ VỀ VÒNG LẶP VÔ HẠN - ĐỪNG CHẠY NẾU KHÔNG BIẾT CÁCH DỪNG!
# (Thường phải nhấn Ctrl + C trong terminal để dừng)

# dem = 0
# while dem < 5:
#     print("Vẫn đang chạy...")
#     # Lỗi: Quên không cập nhật biến 'dem'. 'dem' sẽ luôn là 0.
#     # dem = dem + 1 # Dòng này bị thiếu hoặc bị comment đi

Làm thế nào để tránh?

  1. Luôn đảm bảo có ít nhất một con đường trong khối lệnh while sẽ dẫn đến việc điều kiện trở thành False.
  2. Kiểm tra kỹ các biến tham gia vào điều kiện và đảm bảo chúng được cập nhật đúng cách trong mỗi lần lặp.
  3. Khi sử dụng while True, phải chắc chắn có một lệnh break sẽ được thực thi ở một thời điểm nào đó dưới một điều kiện hợp lý.
  4. Trong quá trình gỡ lỗi (debug), nếu nghi ngờ vòng lặp vô hạn, hãy thêm các lệnh print để theo dõi giá trị của các biến điều kiện qua từng vòng lặp.

Vòng lặp while là một công cụ mạnh mẽ để kiểm soát luồng thực thi của chương trình dựa trên các điều kiện động. Hiểu rõ cách hoạt động, các ví dụ ứng dụng và cách tránh lỗi vòng lặp vô hạn sẽ giúp bạn viết code Python hiệu quả và linh hoạt hơn rất nhiều!

Comments

There are no comments at the moment.