Notes & software courses · Free to learn
Aph's Blog
On this page

Lambda & Higher-Order Functions

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

มองฟังก์ชันเป็น "ค่า" ที่เก็บใส่ตัวแปร ส่งเข้าฟังก์ชันอื่น และคืนกลับได้

ใน Python ฟังก์ชันเป็น "first-class object" — เก็บใส่ตัวแปร ใส่ใน list ส่งเป็น argument และคืนจากฟังก์ชันได้เหมือนข้อมูลทั่วไป ความเข้าใจนี้คือรากฐานของ decorator และโค้ดสไตล์ functional

ฟังก์ชันเป็นค่า

python
def shout(text):
    return text.upper()

f = shout            # เก็บฟังก์ชันใส่ตัวแปร (ไม่มีวงเล็บ = ไม่เรียก)
print(f("hello"))    # HELLO

# ใส่ฟังก์ชันใน list ก็ได้
funcs = [str.upper, str.lower, str.title]
for fn in funcs:
    print(fn("hello World"))   # HELLO WORLD / hello world / Hello World

lambda — ฟังก์ชันไม่มีชื่อแบบสั้น

lambda คือฟังก์ชันบรรทัดเดียวไม่มีชื่อ เหมาะกับงานสั้น ๆ ที่ส่งเข้าฟังก์ชันอื่น โครงสร้าง: lambda พารามิเตอร์: นิพจน์ (คืนค่านิพจน์อัตโนมัติ)

python
square = lambda x: x * x
print(square(5))     # 25

add = lambda a, b: a + b
print(add(2, 3))     # 5

# เทียบกับ def ที่ทำเหมือนกัน
def square_def(x):
    return x * x

sorted(key=...) — ที่ใช้ lambda บ่อยสุด

งานจริงที่ใช้ lambda มากที่สุดคือบอกวิธีเรียงลำดับผ่านพารามิเตอร์ key

python
people = [
    {"name": "Aph", "age": 25},
    {"name": "Bee", "age": 19},
    {"name": "Cha", "age": 31},
]

# เรียงตามอายุ
by_age = sorted(people, key=lambda p: p["age"])
print([p["name"] for p in by_age])    # ['Bee', 'Aph', 'Cha']

# เรียงหลายเงื่อนไข: ตามอายุ แล้วชื่อ
by_multi = sorted(people, key=lambda p: (p["age"], p["name"]))

# เรียงคำตามความยาว
words = ["banana", "kiwi", "apple"]
print(sorted(words, key=len))         # ['kiwi', 'apple', 'banana']

map & filter (และทำไม comprehension มักดีกว่า)

map ใช้ฟังก์ชันกับทุกตัว, filter กรองตามเงื่อนไข — แต่ใน Python นิยม comprehension มากกว่าเพราะอ่านง่ายกว่า ควรรู้จักทั้งคู่

python
nums = [1, 2, 3, 4, 5]

# map / filter (คืน iterator ต้องครอบ list())
doubled = list(map(lambda x: x * 2, nums))
evens = list(filter(lambda x: x % 2 == 0, nums))
print(doubled)   # [2, 4, 6, 8, 10]
print(evens)     # [2, 4]

# แบบ comprehension — Pythonic กว่า อ่านง่ายกว่า
doubled = [x * 2 for x in nums]
evens = [x for x in nums if x % 2 == 0]
แนวทาง

ถ้าเลือกได้ ใช้ comprehension เพราะอ่านง่ายและเป็นสำนวน Python แต่ map/filter ยังมีประโยชน์เมื่อมีฟังก์ชันสำเร็จอยู่แล้ว เช่น map(str, nums) หรือ map(int, lines)

ฟังก์ชันที่รับฟังก์ชัน (Higher-Order)

higher-order function คือฟังก์ชันที่รับฟังก์ชันอื่นเป็น argument หรือคืนฟังก์ชัน — sorted, map, filter ล้วนเป็นแบบนี้ เราเขียนเองได้

python
def apply_twice(func, value):
    return func(func(value))

print(apply_twice(lambda x: x + 3, 10))   # 16  (10+3+3)
print(apply_twice(str.upper, "hi"))       # HI

สรุปหัวข้อนี้

  • ฟังก์ชันเป็นค่า: เก็บใส่ตัวแปร/list, ส่งต่อ, คืนกลับได้
  • lambda = ฟังก์ชันสั้นไม่มีชื่อ: lambda args: นิพจน์
  • ใช้ lambda บ่อยสุดกับ sorted(key=...) — เรียงหลายเงื่อนไขด้วย tuple
  • map/filter ได้ผลเหมือน comprehension แต่ comprehension อ่านง่ายกว่า
แบบฝึกหัด

1) เรียง list ของ tuple (ชื่อ, คะแนน) ตามคะแนนจากมากไปน้อย 2) ใช้ map แปลง ["1","2","3"] เป็น [1,2,3] 3) ใช้ filter เก็บเฉพาะคำยาวเกิน 3 ตัวอักษร 4) เขียน higher-order function ที่รับฟังก์ชันกับ list แล้ว apply ฟังก์ชันกับทุกตัว