On this page
Comprehension เจาะลึก
เขียน list/dict/set ในบรรทัดเดียวแบบ Pythonic — อ่านง่าย เร็ว และรู้ว่าเมื่อไรไม่ควรใช้
comprehension คือวิธีสร้าง list/dict/set จากการวนซ้ำในบรรทัดเดียว เป็นสำนวนที่คุณจะเห็นในโค้ด Python จริงแทบทุกไฟล์ บทย่อยนี้จะพาไปตั้งแต่รูปแบบพื้นฐาน จนถึงการใส่เงื่อนไข การซ้อนชั้น และเส้นที่ "ไม่ควรข้าม" เพื่อรักษาความอ่านง่าย
คอร์สนี้ควรรัน Python บนเครื่องจริงแล้ว เปิด terminal พิมพ์ python หรือเปิดไฟล์ .py แล้วลองรันทุกชิ้น พร้อมแก้ค่าดูผลลัพธ์ — การลงมือทำคือสิ่งที่ทำให้เข้าใจจริง
จาก for-loop สู่ list comprehension
สมมติเราอยากได้ list ของเลขยกกำลังสอง วิธีปกติเขียนด้วย for-loop หลายบรรทัด comprehension ย่อให้เหลือบรรทัดเดียวโดยอ่านได้ว่า "เอา x*x สำหรับทุก x ใน range"
# แบบ for-loop ปกติ
squares = []
for x in range(5):
squares.append(x * x)
print(squares) # [0, 1, 4, 9, 16]
# แบบ list comprehension — ผลเหมือนกันเป๊ะ
squares = [x * x for x in range(5)]
print(squares) # [0, 1, 4, 9, 16]โครงสร้างคือ [นิพจน์ for ตัวแปร in ลำดับ] — ฝั่งซ้ายสุดคือ "สิ่งที่จะเก็บ" ตามด้วย for ที่บอกว่าวนอะไร
ใส่เงื่อนไขด้วย if (กรอง)
เติม if ต่อท้ายเพื่อกรองให้เก็บเฉพาะตัวที่ผ่านเงื่อนไข
# เก็บเฉพาะเลขคู่
evens = [x for x in range(10) if x % 2 == 0]
print(evens) # [0, 2, 4, 6, 8]
# เก็บเลขคู่แล้วยกกำลังสอง
even_sq = [x * x for x in range(10) if x % 2 == 0]
print(even_sq) # [0, 4, 16, 36, 64]if/else แบบนิพจน์ (วางไว้ข้างหน้า)
ถ้าอยากเลือกค่า (ไม่ใช่กรองทิ้ง) ให้ใช้ if/else เป็นนิพจน์วางไว้ "ก่อน" for สังเกตตำแหน่งให้ดี — กรองใช้ if ท้าย, เลือกค่าใช้ if/else หน้า
# แปลงเป็นข้อความ คู่/คี่
labels = ["คู่" if x % 2 == 0 else "คี่" for x in range(5)]
print(labels) # ['คู่', 'คี่', 'คู่', 'คี่', 'คู่']| ต้องการ | ตำแหน่ง if | ตัวอย่าง |
|---|---|---|
| กรองทิ้งบางตัว | ท้ายสุด | [x for x in xs if x > 0] |
| เลือกค่า (เก็บทุกตัว) | หน้า for | [x if x > 0 else 0 for x in xs] |
dict & set comprehension
หลักการเดียวกัน แค่เปลี่ยนวงเล็บ — ใช้ { } และสำหรับ dict ใส่ key: value
# dict comprehension: สร้าง map ของเลข -> กำลังสอง
square_map = {x: x * x for x in range(5)}
print(square_map) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
# set comprehension: เก็บความยาวคำที่ไม่ซ้ำ
words = ["hi", "hello", "hey", "yo"]
lengths = {len(w) for w in words}
print(lengths) # {2, 5, 3} (set ไม่เก็บค่าซ้ำ)nested comprehension (ซ้อนชั้น)
ใช้แผ่ (flatten) list 2 มิติให้เป็นมิติเดียวได้ แต่ลำดับ for เขียนจากนอกเข้าใน เหมือน for-loop ซ้อนกันตามปกติ
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
# flatten: อ่านว่า 'เอา num สำหรับทุก row แล้วทุก num ใน row'
flat = [num for row in matrix for num in row]
print(flat) # [1, 2, 3, 4, 5, 6, 7, 8, 9]ถ้า comprehension ซ้อนเกิน 2 ชั้น หรือมีเงื่อนไขซับซ้อนจนอ่านทีเดียวไม่เข้าใจ ให้กลับไปใช้ for-loop ปกติ — เป้าหมายคือโค้ดอ่านง่าย ไม่ใช่สั้นที่สุด การยัดทุกอย่างในบรรทัดเดียวคือ code smell
สรุปหัวข้อนี้
- โครงสร้าง: [นิพจน์ for ตัวแปร in ลำดับ (if เงื่อนไข)]
- กรองทิ้ง → if ท้ายสุด, เลือกค่า → if/else หน้า for
- เปลี่ยนวงเล็บได้เป็น dict {k: v ...} และ set {x ...}
- ซ้อนได้ แต่เกิน 2 ชั้นเมื่อไร ให้กลับไปใช้ for-loop
1) สร้าง list ของเลขคู่ตั้งแต่ 1-20 ที่ยกกำลังสองแล้ว 2) จาก ["apple","banana","kiwi"] สร้าง dict ที่ key เป็นคำ value เป็นความยาวคำ 3) flatten [[1,2],[3,4],[5,6]] เป็น [1,2,3,4,5,6] 4) จาก list คะแนน สร้าง list ที่ค่า >=50 เป็น "ผ่าน" ที่เหลือเป็น "ตก"