Vòng lặp for và while trong Python

Vòng lặp là cách bạn bảo máy tính làm đi làm lại một việc. Python có hai loại vòng lặp, và việc chọn đúng loại giúp code ngắn gọn hơn nhiều.

Vòng lặp for

Khác với C hay Java, for trong Python không đếm số mà duyệt qua từng phần tử:

ngon_ngu = ["Python", "Go", "Rust"]

for ten in ngon_ngu:
    print(f"Tôi đang học {ten}")

Khi cần đếm, dùng range:

for i in range(5):        # 0, 1, 2, 3, 4
    print(i)

for i in range(2, 10, 2): # 2, 4, 6, 8
    print(i)

for i in range(10, 0, -1):  # đếm ngược
    print(i)

Cần cả chỉ số lẫn giá trị

Người mới hay viết thế này:

for i in range(len(ngon_ngu)):     # cách của ngôn ngữ khác
    print(i, ngon_ngu[i])

Python có cách gọn hơn:

for i, ten in enumerate(ngon_ngu):
    print(i, ten)

for i, ten in enumerate(ngon_ngu, start=1):   # đánh số từ 1
    print(f"{i}. {ten}")

Duyệt hai danh sách cùng lúc

ten = ["An", "Bình", "Cường"]
diem = [8.5, 7.0, 9.2]

for t, d in zip(ten, diem):
    print(f"{t}: {d}")

Lưu ý zip dừng ở danh sách ngắn nhất. Nếu muốn báo lỗi khi độ dài khác nhau, dùng zip(ten, diem, strict=True) — tham số có từ Python 3.10 và rất đáng dùng, vì độ dài lệch nhau thường là dấu hiệu dữ liệu có vấn đề.

Vòng lặp while

Dùng khi bạn không biết trước phải lặp bao nhiêu lần:

tong = 0
while tong < 100:
    n = int(input("Nhập một số: "))
    tong += n
    print(f"Tổng hiện tại: {tong}")

Rủi ro lớn nhất của while là vòng lặp vô tận. Luôn tự hỏi: điều kiện này sẽ sai vào lúc nào?

i = 0
while i < 10:
    print(i)
    # quên i += 1  ->  chạy mãi không dừng

break và continue

for so in [3, 7, 12, 5, 20]:
    if so > 10:
        print(f"Gặp {so}, dừng lại")
        break          # thoát hẳn vòng lặp

for so in range(10):
    if so % 2:
        continue       # bỏ qua phần còn lại, sang vòng kế
    print(so)          # chỉ in số chẵn

Mệnh đề else của vòng lặp

Đây là tính năng ít người biết. Khối else chạy khi vòng lặp kết thúc mà không gặp break:

ds = [4, 8, 15, 16, 23]

for x in ds:
    if x > 100:
        print("Tìm thấy số lớn hơn 100")
        break
else:
    print("Không có số nào lớn hơn 100")

Cách này gọn hơn việc tạo một biến cờ rồi kiểm tra sau vòng lặp.

Vòng lặp lồng nhau

for i in range(1, 4):
    for j in range(1, 4):
        print(f"{i} x {j} = {i*j}")

break chỉ thoát vòng lặp gần nhất. Muốn thoát cả hai, cách sạch nhất là đưa vào hàm rồi return:

def tim(ma_tran, muc_tieu):
    for hang in ma_tran:
        for o in hang:
            if o == muc_tieu:
                return True
    return False

Những lỗi thường gặp

Sửa danh sách trong lúc đang duyệt nó

ds = [1, 2, 3, 4, 5, 6]

for x in ds:
    if x % 2 == 0:
        ds.remove(x)     # SAI - bỏ sót phần tử

print(ds)   # [1, 3, 5] - trông có vẻ đúng nhưng không phải luôn thế

Khi bạn xóa phần tử, các phần tử phía sau dịch lên, còn con trỏ duyệt vẫn tiến tới — kết quả là vài phần tử bị bỏ qua. Hãy tạo danh sách mới:

ds = [x for x in ds if x % 2]

Quên rằng range không bao gồm điểm cuối

for i in range(1, 10):    # chạy từ 1 tới 9, KHÔNG có 10
    print(i)

Khi nào không cần vòng lặp

Python có sẵn nhiều hàm làm thay bạn, vừa ngắn vừa nhanh hơn:

ds = [4, 8, 15, 16, 23, 42]

tong    = sum(ds)
lon_nhat = max(ds)
co_so_le = any(x % 2 for x in ds)
toan_duong = all(x > 0 for x in ds)
da_sap_xep = sorted(ds, reverse=True)

Nếu bạn đang viết vòng lặp chỉ để cộng dồn hoặc tìm giá trị lớn nhất, gần như chắc chắn có sẵn hàm làm việc đó.