พื้นฐาน

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

อัปเดต: · Skillaria.Top

ลูปใน 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 <= 0:
        continue          # ข้ามรอบนี้
    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

คำถามที่พบบ่อย

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

เรียนหัวข้อนี้ผ่านวิดีโอ

หัวข้อนี้สอนอย่างละเอียดพร้อมฝึกปฏิบัติในคอร์ส “Python 3.15: от новичка до профи”

ไปที่คอร์ส