First-class citizen
ในทางคณิตศาสตร์ higher-order function คือ function ที่สามารถทำได้อย่างน้อย 1 อย่างต่อไปนี้ [1]
- 1) รับ function อื่นเป็น input ได้
- 2) ส่ง output ในรูปแบบของ function ได้
โดยทั่วไป หน้าที่หลักของ function คือการกระทำบางอย่างกับกับ input และส่งค่าผลลัพธ์ออกไปเป็น output (แต่บาง funtion ไม่ได้ส่ง output ที่เชื่อมโยงกับ input เช่น print() รับค่าเป็น String แต่ส่งค่า None เป็น output แต่มีการนำ input ไปแสดงบนหน้าจอ เรียกว่า side effect)
Function ในภาษา Python จัดเป็น "first-class object"(first-class citizen)[2] หมายความว่า ตัวของ function เป็นได้หลายรูปแบบ :-
- - assigned to variable
- - defined in another function
- - returned as output
- - passed as argument
การ assign function ให้กับ variable
#-- this is function
def square(x):
return x**2
#-- assign function to variable
pow_2 = square
pow_2(4)
# result is 16
การ define function ภายใน function
#-- function in function
def square(x):
def plus(x,y):
return x + y
_sum = 0
for _ in range(x):
_sum = plus(_sum,x)
return _sum
square(4)
# result is 16
function as argument
def mul(x,y):
return x/2
def plus(x,y):
return x + y
def operate(f1,f2,var1,var2):
result = f2(f1(var1,var2),f1(var2,var1))
return result
v1 = 4
v2 = 3
print(operate(mul,plus,v1,v2))
# result is 3.5
return result as a function
def mul(x,y):
return x/2
def plus(x,y):
return x + y
def operate(f1,f2,var1,var2):
return f2(f1(var1,var2),f1(var2,var1))
v1 = 4
v2 = 3
print(operate(mul,plus,v1,v2))
3.5
Simple decoration
หลังจากเข้าใจกับสิ่งที่เรียกว่า "first-class object" หรือ "first-class citizen" แล้ว ก็มาดูเรื่องการสร้าง decorator กัน เริ่มต้นด้วย
def decorator_func(input_func):
def wrapper():
print("Before input function is executed.")
input_func()
print("After input function is executed.")
return wrapper
def stand_alone_func():
print("I am standalone function, do not modify me.")
#-- decoration happends here
decoration = decorator_func(stand_alone_func)
#-- execute
decoration()
#-- out put is
# Before input function is executed.
# I am standalone function, do not modify me.
# After input function is executed.
พิจารณาดู decorator_func() มีข้อสังเกตุคือ
- 1) การใช้ function เป็น argument
- 2) มี inner function
- 3) return เป็น function
ดูบรรทัดที่มีชุดคำสั่ง decoration = decorator_func(stand_alone_func) การ decorate เกิดขึ้นที่นี่ ขั้นตอนคือการ ส่ง stand_alone_func() ให้เป็น argument ของ decorator_func() ทำให้ชุดคำสั่งภายใน stand_alone_func() ถูกโยงเข้าไปยัง inner function ชื่อ wrapper() ผลที่จะเกิดขึ้นคือการทำงานร่วมกันระหว่างชุดคำสั่งทั้งที่มีอยู่ก่อนแล้วและส่วนที่ถูกส่งเข้าไป แล้วสุดท้ายก็ assign ไปยังตัวแปรชื่อ declaration ขั้นตอนทั้งหมดนี้เหมือนกับการตกแต่ง (decoration) stand_alone_func() ด้วย wrapper function ภายใน decorator_fun()
Syntactic Sugar
การทำ decoration ตามแบบตัวอย่างข้างต้น ใช้งานได้แต่ออกจะเทอะทะไปสักหน่อย ในภาษา Python กำหนดให้ใช้เครื่องหมาย "@" วางไว้หน้าชื่อ decorator function (เรียกว่า pie syntax) ซึ่งจะต้องมีก่อนหน้าการสร้าง stand alone function จากตัวอย่างข้างต้น สามารถเขียนใหม่ด้วย pie syntax เป็น
หลังจากทำ decoration แล้ว เมื่อเรียกใช้ stand alond function ผลที่ได้จะต่างออกไปจากที่กำหนดไว้ ตัวอย่างนี้จะทำให้เห็นหน้าที่ของ decorator function ชัดเจนคือ "การเปลี่ยนแปลงพฤติกรรมของ stand alone function เหมือนการตกแต่ง" พิจารณาตัวอย่างต่อไปนี้
จะเห็นว่าผลของ decoration ทำให้ function ที่ชุดคำสั่งจะระบุให้ return ค่าเดียวกัน ได้ผลออกมาต่างกันได้
def decorator_func(input_func):
def wrapper():
print("Before input function is executed.")
input_func()
print("After input function is executed.")
return wrapper
@decorator_func
def stand_alone_func():
print("I am standalone function, do not modify me.")
stand_alone_func()
#-- out put is
# Before input function is executed.
# I am standalone function, do not modify me.
# After input function is executed.
หลังจากทำ decoration แล้ว เมื่อเรียกใช้ stand alond function ผลที่ได้จะต่างออกไปจากที่กำหนดไว้ ตัวอย่างนี้จะทำให้เห็นหน้าที่ของ decorator function ชัดเจนคือ "การเปลี่ยนแปลงพฤติกรรมของ stand alone function เหมือนการตกแต่ง" พิจารณาตัวอย่างต่อไปนี้
def sqaure(input_func):
def wrapper():
result = input_func()**2
return result
return wrapper
@sqaure
def decorated():
return 5
def undecorated():
return 5
print("Result from decorated change from {} to {}.".format(undecorated(),decorated()))
print("Result from undecorated is still {}.".format(undecorated()))
#-- out put is
# Result from decorated change from 5 to 25.
# Result from undecorated is still 5.
จะเห็นว่าผลของ decoration ทำให้ function ที่ชุดคำสั่งจะระบุให้ return ค่าเดียวกัน ได้ผลออกมาต่างกันได้
อ้างอิง
[1] https://en.wikipedia.org/wiki/Higher-order_function
[2] https://en.wikipedia.org/wiki/First-class_citizen
ความคิดเห็น
แสดงความคิดเห็น