# Vòng lặp và điều kiện trong Python: for, while, range, enumerate, break, if/elif và match/case

URL: https://skillaria.top/vi/guides/python/vong-lap-python

Vòng lặp trong Python dùng để lặp lại một hành động: for duyệt qua từng phần tử của một tập hợp hoặc dãy range(), còn while chạy chừng nào điều kiện còn đúng. Dừng vòng lặp bằng break, bỏ qua một lượt bằng continue, lấy số thứ tự bằng enumerate(). Quyết định được đưa ra bằng điều kiện if/elif/else, còn phân tích dữ liệu theo hình dạng dùng match/case (từ Python 3.10).

Vòng lặp trong Python dùng để lặp lại một hành động: duyệt qua danh sách mua sắm, xử lý từng dòng của một tệp, hỏi người dùng cho đến khi nhập đúng một con số. Python có hai vòng lặp — `for` và `while` — còn bên trong chúng, các điều kiện `if/elif/else` và toán tử `match/case` giúp đưa ra quyết định. Dưới đây là từng công cụ với các ví dụ thực tế.

## Điều kiện: if, elif, else

Câu lệnh điều kiện chỉ thực thi khối code khi biểu thức đúng. Khối được xác định bằng thụt đầu dòng 4 khoảng trắng — Python không dùng dấu ngoặc nhọn, và thụt sai sẽ báo lỗi `IndentationError` ngay.

```
spent = 4200
limit = 5000

if spent > limit:
    print("Vượt hạn mức")
elif spent > limit * 0.8:
    print("Còn dưới 20% ngân sách")
else:
    print("Mọi thứ ổn")
```

Các nhánh `elif` được kiểm tra từ trên xuống, và chỉ nhánh phù hợp đầu tiên được thực thi. Vì vậy hãy đặt điều kiện nghiêm ngặt hơn lên trên: nếu kiểm tra `spent > limit * 0.8` đứng đầu, thông báo vượt hạn mức sẽ không bao giờ xuất hiện.

### Thế nào là đúng

Trong điều kiện không nhất thiết phải viết phép so sánh. Các giá trị được coi là sai gồm `False`, `None`, số không (`0`, `0.0`) và các tập hợp rỗng: `""`, `[]`, `{}`. Mọi thứ còn lại đều là đúng. Vì thế kiểm tra «danh sách không rỗng» được viết rất ngắn gọn:

```
expenses = []
if not expenses:
    print("Chưa có khoản chi nào")
```

Các điều kiện được kết hợp bằng `and`, `or`, `not`, còn kiểm tra một khoảng thì tiện nhất bằng chuỗi so sánh: `if 0 < amount <= 100_000:`. Để chọn giá trị ngắn gọn có toán tử ba ngôi: `status = "nhiều" if spent > limit else "bình thường"`.

## Vòng lặp for trong Python: cú pháp và ví dụ

Vòng lặp `for` trong Python không phải là bộ đếm như trong C, mà là phép duyệt qua các phần tử. Nó lấy lần lượt từng phần tử của một đối tượng có thể lặp: danh sách, chuỗi, dict, tệp, dãy số. Đây chính là foreach của các ngôn ngữ khác.

```
expenses = [350, 1200, 89, 4500]
total = 0
for amount in expenses:
    total += amount
print(total)  # 6139
```

Cú pháp: `for biến in tập_hợp:`, tiếp theo là khối code thụt đầu dòng. Sau vòng lặp, biến vẫn giữ giá trị cuối cùng — đôi khi điều đó hữu ích, nhưng không nên phụ thuộc vào nó trong các chương trình lớn.

### Lặp qua chuỗi, danh sách và dict

Chuỗi được duyệt theo từng ký tự, danh sách theo từng phần tử. Mặc định, vòng lặp qua dict đi theo khóa; để lấy đồng thời khóa và giá trị, dùng `.items()`:

```
by_category = {"ăn uống": 3200, "đi lại": 900, "giải trí": 600}

for category, amount in by_category.items():
    print(f"{category}: {amount} ₫")
```

Nếu chỉ cần giá trị, dùng `.values()`. Không được thay đổi kích thước dict trong lúc đang duyệt — sẽ gặp `RuntimeError: dictionary changed size during iteration`. Khi cần xóa phần tử, hãy duyệt trên một bản sao: `for key in list(d):`.

## Hàm range: vòng lặp qua các số

Khi cần duyệt qua các số, `range()` là lựa chọn phù hợp. Nó không tạo danh sách trong bộ nhớ mà sinh từng số một, nên `range(10**9)` chạy gần như tức thời.

| Lời gọi | Các số |
| --- | --- |

| `range(5)` | 0, 1, 2, 3, 4 |

| `range(2, 6)` | 2, 3, 4, 5 |

| `range(0, 10, 3)` | 0, 3, 6, 9 |

| `range(5, 0, -1)` | 5, 4, 3, 2, 1 |

Quy tắc quan trọng: cận phải không nằm trong dãy. `range(1, 10)` kết thúc ở số 9 — đây là nguyên nhân phổ biến của lỗi «lệch một». Bước có thể âm, nhưng không được bằng 0.

```
for i in range(1, 4):
    print(f"Ngày {i}")
# Ngày 1
# Ngày 2
# Ngày 3
```

## enumerate: bộ đếm trong vòng lặp

Người mới thường viết `for i in range(len(items))` để biết số thứ tự của phần tử. Cách này chạy được nhưng khó đọc. Hàm `enumerate()` trả về các cặp «số thứ tự, phần tử», còn tham số `start` cho biết bắt đầu đếm từ số nào:

```
items = ["cà phê", "taxi", "cơm trưa"]
for n, item in enumerate(items, start=1):
    print(n, item)
# 1 cà phê
# 2 taxi
# 3 cơm trưa
```

Để duyệt song song hai danh sách có hàm `zip()`: `for name, price in zip(names, prices):`. Nó dừng ở danh sách ngắn nhất; từ Python 3.10 có thể truyền `strict=True`, khi đó độ dài khác nhau sẽ gây lỗi.

## Vòng lặp while trong Python

Vòng lặp `while` lặp lại khối code chừng nào điều kiện còn đúng. Nó phù hợp khi trước đó không biết trước số lần lặp: chờ người dùng nhập đúng, đọc dữ liệu đến hết, thử lại yêu cầu cho đến khi thành công.

```
balance = 10_000
month = 0
while balance > 0:
    balance -= 2_700
    month += 1
print(f"Số dư đủ dùng trong {month} tháng")  # 4
```

Rủi ro lớn nhất là quên thay đổi biến có trong điều kiện — khi đó vòng lặp không bao giờ kết thúc. Nếu chương trình bị «treo», nhấn Ctrl+C: Python sẽ dừng việc thực thi với `KeyboardInterrupt`.

### Vòng lặp vô hạn và kiểu do while

Đôi khi vòng lặp vô hạn được viết có chủ đích: `while True:` với lối thoát bằng `break`. Cũng bằng cách này, người ta làm vòng lặp với kiểm tra hậu điều kiện — Python không có cấu trúc `do while`, và kỹ thuật này thay thế nó: khối code chạy ít nhất một lần, còn kiểm tra nằm ở cuối.

```
while True:
    raw = input("Số tiền: ")
    if raw.isdigit():
        amount = int(raw)
        break
    print("Hãy nhập một số nguyên")
```

Vòng lặp for hiếm khi vô hạn — chỉ khi duyệt qua một iterator vô hạn, ví dụ `itertools.count()`.

## break và continue: thoát vòng lặp và bỏ qua một lượt

`break` dừng vòng lặp ngay lập tức, chương trình tiếp tục từ đoạn code phía sau nó. `continue` bỏ phần còn lại của lượt hiện tại và chuyển sang lượt tiếp theo.

```
expenses = [350, -10, 1200, 0, 99_999, 89]

for amount in expenses:
    if amount  50_000:
        print("Số tiền đáng ngờ, dừng lại")
        break             # thoát khỏi vòng lặp
    print(amount)
```

Chương trình sẽ in 350 và 1200, rồi in thông báo — vòng lặp không đi tới 89. Cả hai lệnh chỉ tác động lên vòng lặp gần nhất chứa chúng.

### else của vòng lặp

Vòng lặp `for` và `while` có một nhánh `else` khác thường: nó được thực thi khi vòng lặp kết thúc tự nhiên, không bị `break`. Điều này tiện cho việc tìm kiếm:

```
for amount in expenses:
    if amount > 50_000:
        print("Đã tìm thấy khoản chi lớn")
        break
else:
    print("Không có khoản chi lớn nào")
```

## Vòng lặp lồng nhau

Vòng lặp bên trong một vòng lặp sẽ chạy hết toàn bộ mỗi lần vòng lặp ngoài thực hiện một lượt. Cách này dùng để duyệt bảng, ma trận, các cặp phần tử.

```
for row in range(1, 4):
    for col in range(1, 4):
        print(row * col, end="\t")
    print()
```

Cần lưu ý hai điều. Thứ nhất, độ phức tạp tăng rất nhanh: hai vòng lặp lồng nhau trên 10 000 phần tử là 100 triệu phép xử lý. Thứ hai, `break` chỉ thoát khỏi vòng lặp trong. Muốn dừng cả hai, hãy đưa các vòng lặp vào một hàm và dùng `return` — cách này sạch hơn việc dùng cờ hiệu.

## Toán tử match/case

Từ Python 3.10, chuỗi dài `if cmd == ... elif ...` có thể thay bằng toán tử `match` (PEP 634). Đây không chỉ là switch: nó so khớp giá trị với một mẫu theo hình dạng dữ liệu và tách các phần thành biến ngay lập tức.

```
def parse(text):
    match text.split():
        case ["add", item, amount]:
            return f"Thêm {item}: {amount}"
        case ["list"] | ["ls"]:
            return "Hiển thị các khoản chi"
        case ["quit"]:
            return "Thoát"
        case _:
            return "Lệnh không xác định"

print(parse("add Cà_phê 250"))  # Thêm Cà_phê: 250
print(parse("add Cà_phê"))      # Lệnh không xác định
```

Mẫu danh sách `["add", item, amount]` chỉ khớp với danh sách đúng ba phần tử, trong đó phần tử đầu là `"add"`. Vì vậy lệnh không có số tiền rơi vào nhánh `_`, nhánh bắt mọi trường hợp còn lại. Ký tự `|` gộp các phương án.

### Dict, kiểu dữ liệu và điều kiện canh gác

Mẫu dict chỉ kiểm tra các khóa được liệt kê, các khóa thừa bị bỏ qua. Cấu trúc `int(a)` kiểm tra kiểu và gán giá trị vào biến, còn `if` sau mẫu thêm một điều kiện bổ sung (guard):

```
match event:
    case {"type": "expense", "amount": int(a)} if a > 10_000:
        print("Khoản chi lớn", a)
    case {"type": "expense", "amount": int(a)}:
        print("Khoản chi", a)
```

### Cái bẫy chính của match

Tên trần trong `case` là một phép gán chứ không phải so sánh với biến. `case limit:` khớp với mọi giá trị và ghi nó vào `limit`. Để so sánh với hằng số, phải dùng tên có dấu chấm, ví dụ `case Color.RED:`, hoặc dùng literal.

Cú pháp match gần như không đổi từ 3.10. Trong Python 3.15 đã khắc phục một điểm chưa đối xứng nhỏ: trước đây trong mẫu literal chỉ cho phép dấu trừ trước số, còn bây giờ có thể viết cả `case +1:`. Trên các phiên bản cũ hơn, đoạn code này sẽ báo lỗi cú pháp.

## Lỗi thường gặp trong vòng lặp

- **Thay đổi danh sách khi đang duyệt.** Xóa phần tử trong `for` sẽ làm bỏ sót phần tử bên cạnh. Tốt hơn là tạo danh sách mới: `clean = [x for x in items if x > 0]`.
- **Cận của range.** `range(1, n)` không bao gồm `n`.
- **Quên thay đổi điều kiện trong while** — vòng lặp vô hạn.
- **Nối chuỗi bằng += trong vòng lặp** với khối lượng lớn sẽ chậm hơn `"".join(parts)`.
- **Gán thay vì so sánh**: `if x = 5` là lỗi cú pháp, phép so sánh viết là `==`.

## Bài tập vòng lặp để luyện tập

1. Tính tổng và trung bình của một danh sách khoản chi, bỏ qua các giá trị âm.
2. In bảng cửu chương từ 1 đến 9 bằng vòng lặp lồng nhau.
3. Hỏi người dùng các số cho đến khi họ nhập chuỗi rỗng, rồi in ra số lớn nhất.
4. Tìm số đầu tiên lớn hơn 1000 trong danh sách và thông báo nếu không có (dùng `for ... else`).
5. Phân tích các lệnh `add`, `del`, `list` bằng `match`.

## Tổng kết

Vòng lặp trong Python gồm hai cấu trúc chính: `for` duyệt qua các phần tử của tập hợp hoặc `range()`, còn `while` chạy chừng nào điều kiện còn đúng. `break` và `continue` điều khiển luồng chạy, `enumerate()` và `zip()` giúp bỏ bộ đếm thủ công, còn `if/elif/else` và `match/case` đảm nhiệm việc ra quyết định. Tất cả các công cụ này được thực hành trên ví dụ trình theo dõi chi tiêu trong bài giảng về Python của khóa học.

## FAQ

**for khác while trong Python ở điểm nào?**

for duyệt qua một dãy có sẵn và tự biết khi nào dừng, còn while lặp lại chừng nào điều kiện còn đúng. Nếu số lần lặp đã biết hoặc có một tập hợp để duyệt thì dùng for; nếu bạn đang chờ một sự kiện thì dùng while.

**Làm sao để duyệt vòng lặp theo thứ tự ngược?**

Dùng reversed(items) cho một tập hợp, hoặc range(n - 1, -1, -1) cho các số. Hàm reversed không sao chép danh sách mà duyệt nó từ cuối lên.

**Python có switch không?**

Không có switch riêng; vai trò đó do chuỗi if/elif và toán tử match/case (từ Python 3.10) đảm nhiệm. match làm được nhiều hơn: phân tích danh sách và dict theo hình dạng và gán giá trị vào biến.

**Vòng lặp hay list comprehension nhanh hơn?**

List comprehension dạng [x * 2 for x in items] thường nhanh hơn một chút so với vòng lặp tương đương dùng append, và ngắn gọn hơn. Với logic phức tạp có nhiều điều kiện, vòng lặp thông thường dễ đọc hơn.

**Làm sao thoát ngay khỏi hai vòng lặp lồng nhau?**

break chỉ dừng vòng lặp trong. Cách đơn giản nhất là đưa các vòng lặp vào một hàm và thoát bằng return.


---
Source: Skillaria.Top (https://skillaria.top)
