# ลูปและเงื่อนไขใน Python: for, while, range, enumerate, break, if/elif และ match/case

URL: https://skillaria.top/th/guides/python/python-loops

ลูปใน Python ใช้ทำซ้ำการกระทำ for วนผ่านสมาชิกของคอลเลกชันหรือ range() ส่วน while ทำงานตราบที่เงื่อนไขเป็นจริง หยุดลูปด้วย break ข้ามรอบด้วย continue และได้เลขลำดับด้วย enumerate() ส่วนการตัดสินใจทำด้วย if/elif/else หรือการจับคู่รูปแบบด้วย match/case (ตั้งแต่ Python 3.10)

ลูปใน Python ใช้สำหรับทำซ้ำการกระทำ เช่น ไล่ดูรายการที่ต้องซื้อ ประมวลผลทีละบรรทัดของไฟล์ หรือถามผู้ใช้จนกว่าจะกรอกตัวเลขที่ถูกต้อง ภาษามีลูปสองแบบคือ `for` และ `while` ส่วนการตัดสินใจภายในลูปทำได้ด้วยเงื่อนไข `if/elif/else` และคำสั่ง `match/case` บทความนี้อธิบายเครื่องมือแต่ละตัวพร้อมตัวอย่างที่ใช้งานได้จริง

## เงื่อนไข: if, elif, else

คำสั่งเงื่อนไขจะรันบล็อกโค้ดก็ต่อเมื่อนิพจน์เป็นจริง บล็อกถูกกำหนดด้วยการเยื้อง 4 ช่องว่าง Python ไม่มีวงเล็บปีกกา และการเยื้องผิดจะทำให้เกิดข้อผิดพลาด `IndentationError` ทันที

```
spent = 4200
limit = 5000

if spent > limit:
    print("เกินงบประมาณแล้ว")
elif spent > limit * 0.8:
    print("เหลืองบประมาณน้อยกว่า 20%")
else:
    print("ทุกอย่างเป็นปกติ")
```

กิ่ง `elif` ถูกตรวจจากบนลงล่าง และจะทำงานเฉพาะกิ่งแรกที่ตรงเงื่อนไข ดังนั้นให้วางเงื่อนไขที่เข้มงวดกว่าไว้ด้านบน หากวางการตรวจ `spent > limit * 0.8` ไว้ก่อน ข้อความว่าเกินงบประมาณจะไม่มีวันปรากฏ

### อะไรถือว่าเป็นจริง

ในเงื่อนไขไม่จำเป็นต้องเขียนการเปรียบเทียบเสมอไป ค่าที่ถือว่าเท็จได้แก่ `False` `None` ศูนย์ (`0`, `0.0`) และคอลเลกชันว่าง ได้แก่ `""` `[]` `{}` ค่าอื่นทั้งหมดเป็นจริง ดังนั้นการตรวจว่า "ลิสต์ไม่ว่าง" เขียนได้สั้น ๆ ดังนี้:

```
expenses = []
if not expenses:
    print("ยังไม่มีรายจ่าย")
```

เงื่อนไขรวมกันได้ด้วย `and` `or` `not` และการตรวจช่วงค่าทำได้สะดวกด้วยการเปรียบเทียบต่อกัน เช่น `if 0 < amount <= 100_000:` สำหรับการเลือกค่าแบบสั้น ๆ มีตัวดำเนินการสามส่วน (ternary): `status = "สูง" if spent > limit else "ปกติ"`

## ลูป for ใน Python: ไวยากรณ์และตัวอย่าง

ลูป `for` ใน Python ไม่ใช่ตัวนับแบบภาษา C แต่เป็นการวนผ่านสมาชิกทีละตัว มันหยิบแต่ละสมาชิกของอ็อบเจกต์ที่วนซ้ำได้ เช่น ลิสต์ สตริง ดิกชันนารี ไฟล์ หรือช่วง range ลูปแบบ foreach ในภาษาอื่นก็คือ `for` ธรรมดานี่เอง

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

รูปแบบไวยากรณ์คือ `for ตัวแปร in คอลเลกชัน:` ตามด้วยบล็อกที่เยื้อง ตัวแปรหลังลูปจะยังคงเก็บค่าสุดท้ายไว้ บางครั้งก็มีประโยชน์ แต่ไม่ควรพึ่งพาพฤติกรรมนี้ในโปรแกรมขนาดใหญ่

### วนลูปสตริง ลิสต์ และดิกชันนารี

สตริงถูกวนทีละอักขระ ลิสต์ถูกวนทีละสมาชิก ส่วนการวนดิกชันนารีจะได้คีย์เป็นค่าเริ่มต้น หากต้องการทั้งคีย์และค่าพร้อมกันให้ใช้ `.items()`

```
by_category = {"อาหาร": 3200, "เดินทาง": 900, "หนัง": 600}

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

หากต้องการเฉพาะค่า ใช้ `.values()` ห้ามเปลี่ยนขนาดดิกชันนารีระหว่างการวน ไม่เช่นนั้นจะได้ `RuntimeError: dictionary changed size during iteration` หากต้องการลบรายการระหว่างวน ให้วนบนสำเนา: `for key in list(d):`

## ฟังก์ชัน range: ลูปผ่านตัวเลข

เมื่อต้องวนผ่านตัวเลข ให้ใช้ `range()` มันไม่สร้างลิสต์ในหน่วยความจำ แต่ให้ตัวเลขทีละตัว ดังนั้น `range(10**9)` จึงทำงานได้ทันที

| การเรียก | ตัวเลขที่ได้ |
| --- | --- |

| `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 |

กฎสำคัญคือขอบเขตด้านขวาไม่รวมอยู่ในช่วง `range(1, 10)` จะจบที่ 9 ซึ่งเป็นสาเหตุของข้อผิดพลาด "ผิดไปหนึ่ง" ที่พบบ่อย ค่าขั้น (step) ติดลบได้ แต่ห้ามเป็นศูนย์

```
for i in range(1, 4):
    print(f"วันที่ {i}")
# วันที่ 1
# วันที่ 2
# วันที่ 3
```

## enumerate: ตัวนับในลูป

มือใหม่มักเขียน `for i in range(len(items))` เพื่อรู้ลำดับของสมาชิก วิธีนี้ใช้ได้แต่อ่านยาก ฟังก์ชัน `enumerate()` คืนคู่ "ลำดับ, สมาชิก" และพารามิเตอร์ `start` กำหนดว่าจะเริ่มนับจากเลขใด

```
items = ["กาแฟ", "แท็กซี่", "อาหารกลางวัน"]
for n, item in enumerate(items, start=1):
    print(n, item)
# 1 กาแฟ
# 2 แท็กซี่
# 3 อาหารกลางวัน
```

สำหรับการวนสองลิสต์พร้อมกันใช้ `zip()` เช่น `for name, price in zip(names, prices):` ซึ่งจะหยุดเมื่อถึงลิสต์ที่สั้นที่สุด ตั้งแต่ Python 3.10 สามารถส่ง `strict=True` ได้ หากความยาวไม่เท่ากันจะเกิดข้อผิดพลาดทันที

## ลูป while ใน Python

ลูป `while` ทำซ้ำบล็อกตราบที่เงื่อนไขเป็นจริง ใช้เมื่อไม่รู้จำนวนรอบล่วงหน้า เช่น รอการกรอกค่าที่ถูกต้อง อ่านข้อมูลจนหมด หรือลองขอข้อมูลซ้ำจนสำเร็จ

```
balance = 10_000
month = 0
while balance > 0:
    balance -= 2_700
    month += 1
print(f"เงินพอใช้ได้ {month} เดือน")  # 4
```

อันตรายหลักคือการลืมเปลี่ยนค่าตัวแปรที่อยู่ในเงื่อนไข ลูปจะไม่มีวันจบ หากโปรแกรมค้าง ให้กด Ctrl+C Python จะหยุดการทำงานด้วย `KeyboardInterrupt`

### ลูปไม่สิ้นสุดและ do while

บางครั้งตั้งใจเขียนลูปไม่สิ้นสุดด้วย `while True:` แล้วออกด้วย `break` ใน Python ไม่มีคำสั่ง `do while` และรูปแบบที่ใช้แทนคือลูปที่ตรวจเงื่อนไขไว้ท้ายสุด เพื่อให้บล็อกทำงานอย่างน้อยหนึ่งครั้ง

```
while True:
    raw = input("จำนวนเงิน: ")
    if raw.isdigit():
        amount = int(raw)
        break
    print("กรุณาพิมพ์จำนวนเต็ม")
```

ลูป for ที่ไม่สิ้นสุดพบได้น้อย มักเกิดเมื่อวนผ่านตัววนซ้ำที่ไม่มีที่สิ้นสุด เช่น `itertools.count()`

## break และ continue: ออกจากลูปและข้ามรอบ

`break` หยุดลูปทันที และการทำงานไปต่อที่โค้ดหลังลูป ส่วน `continue` ข้ามส่วนที่เหลือของรอบปัจจุบัน แล้วไปยังรอบถัดไป

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

for amount in expenses:
    if amount  50_000:
        print("จำนวนเงินน่าสงสัย หยุดการทำงาน")
        break             # ออกจากลูป
    print(amount)
```

โค้ดนี้จะพิมพ์ 350 และ 1200 จากนั้นแสดงข้อความแจ้งเตือน และลูปจะไม่ไปถึง 89 ทั้งสองคำสั่งมีผลเฉพาะลูปที่อยู่ใกล้ที่สุดเท่านั้น

### else ของลูป

`for` และ `while` มีบล็อก `else` ที่ไม่ค่อยพบในภาษาอื่น บล็อกนี้จะทำงานเมื่อลูปจบเองตามปกติ โดยไม่ถูก `break` ซึ่งเหมาะกับการค้นหา:

```
for amount in expenses:
    if amount > 50_000:
        print("พบรายจ่ายจำนวนมาก")
        break
else:
    print("ไม่มีรายจ่ายจำนวนมาก")
```

## ลูปซ้อนกัน

ลูปที่อยู่ในลูปจะรันลูปด้านในทั้งหมดในทุกรอบของลูปด้านนอก ใช้สำหรับวนตาราง เมทริกซ์ หรือสร้างคู่ของค่า

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

ควรระวังสองเรื่อง ประการแรก ความซับซ้อนเพิ่มขึ้นอย่างรวดเร็ว ลูปซ้อนสองชั้นที่ทำกับข้อมูลชั้นละ 10 000 รายการจะเป็น 100 ล้านการทำงาน ประการที่สอง `break` ออกจากลูปด้านในเท่านั้น หากต้องการหยุดทั้งสองลูป ให้ย้ายลูปไปไว้ในฟังก์ชันแล้วใช้ `return` ซึ่งอ่านง่ายกว่าการใช้ตัวแปรธง (flag)

## คำสั่ง match/case

ตั้งแต่ Python 3.10 เราสามารถแทนที่โซ่ยาว ๆ ของ `if cmd == ... elif ...` ด้วยคำสั่ง `match` (PEP 634) นี่ไม่ใช่แค่ switch มันเปรียบเทียบค่ากับรูปแบบ (pattern) ตามโครงสร้างของข้อมูล และแยกส่วนประกอบออกมาเป็นตัวแปรทันที

```
def parse(text):
    match text.split():
        case ["add", item, amount]:
            return f"เพิ่ม {item}: {amount}"
        case ["list"] | ["ls"]:
            return "แสดงรายจ่าย"
        case ["quit"]:
            return "ออก"
        case _:
            return "ไม่รู้จักคำสั่งนี้"

print(parse("add กาแฟ 250"))  # เพิ่ม กาแฟ: 250
print(parse("add กาแฟ"))      # ไม่รู้จักคำสั่งนี้
```

รูปแบบลิสต์ `["add", item, amount]` จะตรงกับลิสต์ที่มีสามสมาชิกพอดี และสมาชิกตัวแรกต้องเป็น `"add"` ดังนั้นคำสั่งที่ไม่มีจำนวนเงินจะตกไปยังกิ่ง `_` ที่รับทุกกรณีที่เหลือ เครื่องหมาย `|` รวมตัวเลือกหลายแบบเข้าด้วยกัน

### รูปแบบดิกชันนารี เงื่อนไขเสริม และการตรวจชนิด

รูปแบบดิกชันนารีจะตรวจเฉพาะคีย์ที่ระบุไว้ คีย์อื่นที่เหลือจะถูกละเว้น การเขียน `int(a)` ตรวจชนิดข้อมูลและเก็บค่าไว้ในตัวแปร ส่วน `if` ที่ตามหลังรูปแบบเป็นเงื่อนไขเพิ่มเติม (guard):

```
match event:
    case {"type": "expense", "amount": int(a)} if a > 10_000:
        print("รายจ่ายจำนวนมาก", a)
    case {"type": "expense", "amount": int(a)}:
        print("รายจ่าย", a)
```

### กับดักหลักของ match

ชื่อที่เขียนเปล่า ๆ ใน `case` คือการจับค่า ไม่ใช่การเปรียบเทียบกับตัวแปร `case limit:` จะตรงกับทุกค่าและบันทึกค่านั้นลงใน `limit` หากต้องการเปรียบเทียบกับค่าคงที่ ให้ใช้ชื่อที่มีจุดนำหน้า เช่น `case Color.RED:` หรือใช้ค่าลิเทอรัล

ไวยากรณ์ match ตั้งแต่ 3.10 แทบไม่เปลี่ยนแปลง ใน Python 3.15 มีการปรับความไม่สมมาตรเล็กน้อย: ก่อนหน้านี้รูปแบบลิเทอรัลรองรับเฉพาะเครื่องหมายลบหน้าตัวเลข ตอนนี้สามารถเขียน `case +1:` ได้ด้วย โค้ดนี้จะให้ข้อผิดพลาดด้านไวยากรณ์บนเวอร์ชันเก่ากว่า

## ข้อผิดพลาดที่พบบ่อยในลูป

- **แก้ไขลิสต์ระหว่างการวน** การลบสมาชิกใน `for` ทำให้ข้ามตัวที่อยู่ติดกัน ควรสร้างลิสต์ใหม่: `clean = [x for x in items if x > 0]`
- **ขอบเขตของ range** `range(1, n)` ไม่รวม `n`
- **ลืมเปลี่ยนเงื่อนไขใน while** ทำให้เป็นลูปไม่สิ้นสุด
- **ต่อสตริงด้วย += ในลูป** เมื่อข้อมูลมากจะช้ากว่า `"".join(parts)`
- **ใช้การกำหนดค่าแทนการเปรียบเทียบ** `if x = 5` เป็นข้อผิดพลาดด้านไวยากรณ์ การเปรียบเทียบเขียนด้วย `==`

## โจทย์ฝึกเกี่ยวกับลูป

1. คำนวณผลรวมและค่าเฉลี่ยของรายการค่าใช้จ่าย โดยข้ามค่าติดลบ
2. พิมพ์ตารางสูตรคูณ 1–9 ด้วยลูปซ้อนกัน
3. ถามตัวเลขจากผู้ใช้จนกว่าจะกรอกบรรทัดว่าง แล้วแสดงค่าสูงสุด
4. หาตัวเลขตัวแรกที่มากกว่า 1000 ในลิสต์ และแจ้งหากไม่พบ (ด้วย `for ... else`)
5. แยกวิเคราะห์คำสั่ง `add` `del` และ `list` ด้วย `match`

## สรุป

ลูปใน Python มีสองรูปแบบหลัก คือ `for` ที่วนผ่านคอลเลกชันหรือ `range()` และ `while` ที่ทำงานตราบที่เงื่อนไขยังเป็นจริง `break` และ `continue` ควบคุมการไหลของลูป `enumerate()` และ `zip()` ช่วยให้ไม่ต้องนับเอง ส่วน `if/elif/else` และ `match/case` รับผิดชอบการตัดสินใจ เครื่องมือทั้งหมดนี้ถูกสาธิตผ่านโปรแกรมบันทึกค่าใช้จ่ายในบทเรียนของคอร์ส Python

## FAQ

**for ต่างจาก while ใน Python อย่างไร?**

for วนผ่านลำดับที่มีอยู่แล้วและรู้เองว่าควรหยุดเมื่อใด ส่วน while จะทำซ้ำตราบที่เงื่อนไขเป็นจริง หากรู้จำนวนรอบหรือมีคอลเลกชันให้วน ใช้ for หากต้องรอเหตุการณ์บางอย่าง ใช้ while

**จะวนลูปย้อนหลังได้อย่างไร?**

ใช้ reversed(items) สำหรับคอลเลกชัน หรือ range(n - 1, -1, -1) สำหรับตัวเลข ฟังก์ชัน reversed ไม่คัดลอกลิสต์ แต่วนจากปลายไปต้น

**Python มี switch หรือไม่?**

ไม่มี switch แบบแยกต่างหาก หน้าที่นั้นทำโดยโซ่ if/elif และคำสั่ง match/case ที่มาใน Python 3.10 match ทำได้มากกว่า เช่น แยกลิสต์และดิกชันนารีตามรูปร่าง และจับค่าได้

**ลูปกับการสร้างลิสต์แบบย่อ อันไหนเร็วกว่า?**

การสร้างลิสต์แบบย่อ เช่น [x * 2 for x in items] มักเร็วกว่าลูปที่ใช้ append เล็กน้อย และสั้นกว่า แต่สำหรับตรรกะซับซ้อนที่มีหลายเงื่อนไข ลูปธรรมดาจะอ่านง่ายกว่า

**จะออกจากลูปซ้อนสองชั้นพร้อมกันได้อย่างไร?**

break หยุดเฉพาะลูปด้านในเท่านั้น วิธีที่ง่ายที่สุดคือย้ายลูปไปไว้ในฟังก์ชันแล้วออกด้วย return


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