ว่าด้วยเรื่องของ python decorator ฉบับ โง่สัสๆ

iTUTOR - Theppasith N.
iTUTOR
Published in
2 min readOct 21, 2021

--

คือจริงๆ ใช้ 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/b
print(divide(1,0))
>b is zero - we dont like divide by zero
>None
print(divide(1,5))
>0.2

ท้ายที่สุดนี้ ก็อย่าลืมล้างมือกันนะคับผม :)

จดไว้กันลืม อุอิ

--

--

iTUTOR - Theppasith N.
iTUTOR

A Robotics Software Engineer - Not a quick learner , but eager to learn. — http://www.itutor.name