上週面試被問到 python decorator,這下尷尬了......
我只會用但我不會寫 decorator,雖然在引導下有做出來,但是......好吧,希望我可以被錄取,拜偷。有錄取我明年就投稿 COSCUP 跟 MOPCON!(發願)
因為對 decorator 的概念不熟,所以趕緊找時間惡補一下,發現其實並不難理解。
可以簡單理解成將 function A 丟到 function B 裡面,得到的結果是 function A 再加上 function B。
只不過這個 function A 可以由任何的 function 取代,也就是丟進去的 function 可以是任何一個 function,而結果都會被 function B 包過一層。
餵進去的是 function,吐出來的也是 function。
因為是寫給自己看的所以就沒什麼潤飾了
我們先寫一個自我介紹的 func,他會回傳一個字串裡面寫著 "HI, I'm {your_name}",如果沒有傳入任何參數,那預設你就叫做 john。
def introduceMySelf(name="john"):
introduction = f"""HI, I'm {name}"""
return introduction
if __name__ == "__main__":
print(introduceMySelf())
# HI, I'm john
因為我是個比較害羞怕生的人,所以我在說出自己名字之前會先發出 zmmmm 的聲音。這邊我用一個裝飾子幫我做發出 zmmmm 的聲音。
def sayHello(func):
# inner_function
def wrapper(*args, **kwargs):
print("Zmmmm.....")
res = func(*args, **kwargs)
return res
return wrapper
裝飾子的內容是這樣。我們在 func 中再寫一個 func,他會把傳入的 func 外面再包上其他東西後丟回去,最後整個 func 就會丟出一個 wrapper 的 inner function(所以會說餵進去的是 func,吐出來的也是 func)。
我們把裝飾子拿來用就變成:
def sayHello(func):
# inner_function
def wrapper(*args, **kwargs):
print("Zmmmm.....")
res = func(*args, **kwargs)
return res
return wrapper
@sayHello
def introduceMySelf(name="john"):
introduction = f"""HI, I'm {name}"""
return introduction
if __name__ == "__main__":
print(introduceMySelf())
# Zmmmm.....
# HI, I'm john
面試時還有被問到 list 跟 dict 的 unpack,其實知道怎麼用,但不知道為什麼當下居然愣住,只想到 dict 的 unpack 該怎麼使用,總之順便記下來。
def wrapper(*args, **kwargs):
print("Zmmmm.....")
res = func(*args, **kwargs)
return res
在 wrapper 中用 *args 接受 list 型別的物件,**kwargs 接受 dict 型別的物件。
所以丟入 list 型別的物件可以處理:
print(introduceMySelf("jojo"))
這是代表說其實丟進去的值是一個 list 的型別,進去之後會自動 unpack 這個 list 拿到參數。
丟入 dict 型別的物件時則可以準確抓取鍵值:
print(introduceMySelf(name="mary"))
這是說丟進去是一個 dict 的型別,進去之後會自動 unpack 這個 dict 拿到參數,後續就可以針對特定的 parameter 做處理。
完整範例程式法可以參照
def sayHello(func):
# inner_function
def wrapper(*args, **kwargs):
print("Zmmmm.....")
res = func(*args, **kwargs)
return res
return wrapper
@sayHello
def introduceMySelf(name="john"):
introduction = f"""HI, I'm {name}"""
return introduction
if __name__ == "__main__":
print(introduceMySelf())
# Zmmmm.....
# HI, I'm john
print()
print(introduceMySelf("jojo"))
# Zmmmm.....
# HI, I'm jojo
print()
print(introduceMySelf(name="mary"))
# Zmmmm.....
# HI, I'm john
print()
print(introduceMySelf.__name__)
# wrapper
在上一個範例中最後一行可以發現我們印出來的值是 wrapper。
為什麼?不是應該是 introduceMySelf 才對嗎?
其實我也不知道
不過 python 有內建一個 wraps 的工具,只要修改一些小地方就可以了。
from functools import wraps
def sayHello(func):
# inner_function
@wraps(func)
def wrapper(*args, **kwargs):
print("Zmmmm.....")
res = func(*args, **kwargs)
return res
return wrapper
@sayHello
def introduceMySelf(name="john"):
introduction = f"""HI, I'm {name}"""
return introduction
if __name__ == "__main__":
print(introduceMySelf())
# Zmmmm.....
# HI, I'm john
print()
print(introduceMySelf("jojo"))
# Zmmmm.....
# HI, I'm jojo
print()
print(introduceMySelf(name="mary"))
# Zmmmm.....
# HI, I'm john
print()
print(introduceMySelf.__name__)
# introduceMySelf
感謝有看到最後的你,雖然我不知道你看不看得懂我在寫什麼。
如果覺得有幫助到你,還請幫我按讚、訂閱、按下小鈴鐺唷!
或是給我一份工作