ว่าด้วยเรื่องของ python decorator ฉบับ โง่สัสๆ
คือจริงๆ ใช้ python มานานมาก แล้วแบบว่า ยังไม่ค่อยเข้าใจเรื่อง Decorator Function เท่าไร เลยพยายามจะทำความเข้าใจกับมันให้มากขึ้น
ที่นี้ ในช่วงปีที่เขียนบทความนี้อยู่ (2021) ยังมี COVID-19 ระบาดอยู่
— เลยอยากยกตัวอย่างที่รู้สึกว่าใกล้ตัวหน่อย
“ ล้างมือก่อนทำอะไรก็ตาม จะปลอดภัยจาก Covid นะจ๊ะ ~!”
เราจะสมมติว่าเราเป็นพ่อครัวที่จะต้องหั่นผัก
# Python Code
def cut_veggie():
print("หั่นผัก")
เวลาจะใช้งานก็
cut_veggie()
> หั่นผัก
แต่ในปัจจุบัน เราจะทำอะไรก็ตาม เราควรจะล้างมือก่อน
เราอยากทำให้ Operation ต่าง ไม่ว่าจะหั่นผัก
หรือ ทำอย่างอื่นเช่น (สับหมู , เจียวไข่) ก็ต้องล้างมือให้สะอาดก่อนเสมอ
จะต้องทำยังไงอะ?
เพิ่มการล้างมือไง !
def cut_veggie():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~") # ต้องเพิ่มการล้างมือเข้าไปด้วย
print("หั่นผัก")
ซึ่ง ถ้า Operation ในครัวเรามีหลายอย่าง ความบรรลัยก็จะเกิดขึ้น แบบนี้
def cut_veggie():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~") # ต้องเพิ่มการล้างมือเข้าไปด้วย
print("หั่นผัก")def cut_pork():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~") # ต้องเพิ่มการล้างมือเข้าไปด้วย
print("หั่นหมู")def do_omelette():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~") # ต้องเพิ่มการล้างมือเข้าไปด้วย
print("เจียวไข่") def ......
print("ล้างมือ ล้าง ล้าง ล้างมือ ~") # ต้องเพิ่มการล้างมือเข้าไปด้วย
แม่งไล่เติมแม่งทุก function เลย บักห่าเอ้ยยย 555555555555
เนี่ย เติมหลายๆจุด Copy Paste เก่งจัด — เดี๋ยวก็พลาด
เพราะฉะนั้น เราอยากจะทำให้ function หรือการกระทำทุกๆอย่างของเรา ผ่านการล้างมือก่อน ซึ่งบางทีอาจซับซ้อนกว่า print บรรทัดหนาๆ 1 บรรทัดที่เน้นไว้ ในกรอบด้านบน
มันเลยมีสิ่งที่เรียกว่า decorator ซึ่งเป็น function ที่ รับ function เข้าไป
(เรียกว่า higher-order function หล่อๆ)
พูดโง่ๆเลย ก็คือ เราจะแอบทำบางอย่างก่อน ที่จะทำ function นั้น
เดี๋ยวเราจะรับ function ทำครัวทั้งหลายเราเข้าไป
(cut_veggie, cut_pork, do_omelette) แล้วทำให้มันผ่านการล้างมือก่อน
หน้าตาจะเป็นแบบนี้
# รับโครงของ function เข้าไป (แบบยังไม่เรียกใช้ รับแค่โครงสร้าง)
def hand_wash(func):
# สร้าง inner function (มองโง่ๆคือสร้าง function ลอยๆขึ้นมาแหละ)
def new_modified_function():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~")
func() # ตรงนี้จะเป็นการเรียก func (ของเดิม ที่จะถูกส่งเข้ามา) return new_modified_function
hand_wash เราจะเรียกมันว่า decorator นั่นเอง
—
ใช้ยังไงอ้ะ
ใช้แบบนี้เลยไอ้น้อง — ใช้เครื่องหมาย @ แล้วตามด้วย ชื่อ decorator โลด
def hand_wash(func):
def new_modified_function():
print("ล้างมือ ล้าง ล้าง ล้างมือ ~")
func()
return new_modified_function@hand_wash
def cut_veggie():
print("หั่นผัก")@hand_wash
def cut_pork():
print("หั่นหมู")@hand_wash
def do_omelette():
print("เจียวไข่")
หลังจากนี้ เวลาเรียก function ต่างๆเหล่านี้ จะออกมาเป็นแบบนี้เสมอ
cut_veggie()
> ล้างมือ ล้าง ล้าง ล้างมือ ~
> หั่นผักcut_pork()
> ล้างมือ ล้าง ล้าง ล้างมือ ~
> หั่นหมูdo_omelette()
> ล้างมือ ล้าง ล้าง ล้างมือ ~
> เจียวไข่
ล้างมือกันทุก Operation กันไปเลย แบบโรคจิตระแวงโควิดด 555555555555
Use cases ที่เห็นง่ายๆเลยก็คือ พวก check ความถูกต้องของ input ที่จะยัด function เช่น
def no_zero_division(func):
# เราจะสร้าง func ใหม่ ที่ระวังการหาร 0 ให้
# inner เลยจะต้องมีปริมาณ param 2 ตัวเหมือน func
# ถามว่ารู้ได้ไง - ต้องรู้ก่อนเขียนนะจ๊ะ 555555 def inner(a,b):
if b == 0:
print("b is zero - we dont like divide by zero")
return None
else:
return func(a,b)
return inner
@no_zero_division
def divide(a,b):
return a/bprint(divide(1,0))
>b is zero - we dont like divide by zero
>Noneprint(divide(1,5))
>0.2
ท้ายที่สุดนี้ ก็อย่าลืมล้างมือกันนะคับผม :)
จดไว้กันลืม อุอิ