Python: decorator คืออะไร
ในบทความนี้จะแนะนำเกี่ยวกับ @ ที่เราเรียกมันว่า decorator ในภาษา Python จริงๆแล้วมันคือ ตัวที่เอาไว้ตกแต่ง function หรือ class ฉะนั้นในการใช้จึงต้องวางไว้ด้านบนของ function หรือ class นั่นเอง (เพราะมันคือ function ที่ครอบ function อีกที)
หลักการของมันคือ การ pass function เข้าไปใน function (ปกติการ pass argument เข้าไป เราจะนึกถึงแค่ค่าคงที่หรือตัวแปรเท่านั้น แต่จริงๆแล้ว function ก็สามารถ pass เข้าไปได้เช่นกัน)
หรือ อธิบายเชิงวิชาการ มันคือ
design pattern
ที่จะช่วยextend
หรือmodify
ความสามารถของfucntion
หรือclass
นั้นๆ โดยที่เราไม่ต้องไปเปลี่ยนsource code
ในส่วนนั้น
Ex1:
import time
def logging_time(func):
def logger():
start = time.time() # The current Unix epoch time
print('start = ', start)
func()
print(f"Calling {func.__name__}: {time.time() - start:.5f}")
return logger
@logging_time
def calculate_sum():
return sum(range(100000000)) # This line just want to delay during calculate.
calculate_sum()
อธิบายตามนี้ครับ
การทำงานหลังจากที่มีการเรียกใช้ function calculate_sum() จะเร่ิมจาก
1. Functioncalculate_sum()
จะถูก pass เข้าไปที่ decorator logging_time() ก่อนโดยมีตัวแปร func มารับ
2. จากนั้นจะเข้าไปทำงานที่ function logger() โดยหาค่า current Unix epoch time ออกมาในบรรทัดที่ 5
3. จากนั้นมาที่บรรทัดที่ 7 คือ execute function calculate_sum() ผ่านทางตัวแปร func() เลย
4. มาที่บรรทัดที่ 13 เพื่อรอให้ sum(range(100000000)) ทำเสร็จก่อน (แค่ simulate ให้เหมือนว่ามีการคำนวณอะไรบางอย่างเฉยๆ)
5. เมื่อคำนวณในบรรทัดที่ 13 เสร็จแล้ว จะกลับไปทำงานที่บรรทัดที่ 8 ต่อ คือ คำนวณเวลาที่ใช้ไปโดยแสดงเป็นทศนิยม 5 ตำแหน่ง
6. กลับมาที่ calculate_sum() เป็นอันสิ้นสุดการทำงาน
Ex2: เป็นการพื้นที่รูปวงกลมและวงรี ซึ่งจะพบว่ามีจุดทศนิยมค่อนข้างเยอะเลย
เราสามารถ implement เพิ่มโดยสร้าง decorator มาครอบได้เลย โดยเริ่มจากสร้าง decorator function เป็น template แบบนี้ก่อน
def new_format_number(func):
def new_function():
func()
return new_function
จากนั้นให้ implement func ที่รับเข้าไปเพิ่ม โดยให้สามารถรับ argument ได้ด้วย *args, **kwargs เพื่อให้รับค่ากี่ตัวก็ได้ จากนั้นก้อ reformat ใหม่ตามบรรทัดที่ 6 ก่อนจะ return ออกไป
Ex3: เป็นการประยุกต์ใช้ time
ในการตรวจเช็คเวลาทั้งหมด ที่ฟังก์ชันใช้ในการทำงาน
import time
def timer(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
import pdb; pdb.set_trace()
end_time = time.time()
print(f"Executed {func.__name__} in {end_time - start_time:.6f} seconds.")
return result
return wrapper
@timer
def long_running_function():
time.sleep(2)
long_running_function()
# Output: "Executed long_running_function in 2.000208 seconds."
สรุป : การใช้ decorator function เพื่อตกแต่งเปลี่ยน function นึงให้มีการทำงานมากขึ้น
PS: เราสามารถใช้งาน multi decorator
ได้ด้วย โดยการทำงานจะ execute
จากล่างขึ้นบนนะ เช่น
def lowercase_decorator(function):
def wrapper(arg):
func = function(arg)
string_lowercase = func.lower()
return string_lowercase
return wrapper
def splitter_decorator(function):
def wrapper(arg):
func = function(arg)
string_split = func.split()
return string_split
return wrapper
@splitter_decorator
@lowercase_decorator
def get_list_of_lowercase_word(input):
return input
print(get_list_of_lowercase_word('HeLLo WoRlD'))
print(get_list_of_lowercase_word('Q Electronics'))