ลูปและเงื่อนไขใน Python: for, while, range, enumerate, break, if/elif และ match/case
ลูปใน 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–9 ด้วยลูปซ้อนกัน
- ถามตัวเลขจากผู้ใช้จนกว่าจะกรอกบรรทัดว่าง แล้วแสดงค่าสูงสุด
- หาตัวเลขตัวแรกที่มากกว่า 1000 ในลิสต์ และแจ้งหากไม่พบ (ด้วย
for ... else) - แยกวิเคราะห์คำสั่ง
adddelและ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: от новичка до профи”
ไปที่คอร์ส