iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0

昨天談完 Decorator 的原理 Closure,今天就正式進入 Decorator。

What is Decorator

Decorator 是 Python 的一種語法糖(Syntactic sugar),語法糖指的是,加入這種語法對程式語言的功能沒有影響,但是更方便開發者使用。 decorator 允許開發者在不修改原始 function 的前提下,可以擴展或修改該 function,因此 decorator 本質上就是輸入一個 function,再返回一個擴展或修改的 function 回來。

decorator 本身就是 callable 的 function,在定義 decorator 時,會在這個 function 前加上 @。
簡單例子如下:

def go_pass():
    pass

@go_pass
def a():
    print(1)

那它是如何運作的呢?

昨天談 Closure 時,我們知道在 Python 中,function 可以被傳遞到其他的 function 中,且 function 的返回值可以是一個 function。
decorator 其實就是利用這個特性,一樣來一個簡單的例子:

def dec(func):
    def wrapper():
        print("before function")
        func()
        print("after function")
    return wrapper

@dec
def hello():
    print("Hello World!")

hello()
# before function
# Hello World!
# after function

這裡 decorator 的用法是先把 hello 丟進 dec function,並返回 wrapper , wrapper會把原來丟進去的 function 前後加上 print("before function")print("after function"),所以才會看到印出 Hello World! 前後有 before functionafter function

解釋了這麼多,其實最簡單的解釋就是 @dec hello() 完全等同於 hello = decorator(hello)

def hello():
    print("Hello World!")
    
hello = dec(hello)  # 完全等同於 decorator 
hello()
# before function
# Hello World!
# after function

input output 一定都要是 functions 嗎?

前面有提到我們使用 decorator,input 和 output 都會是 function。
但你說它能不能不返回 function? 可以,只是沒人會這樣用 XD

def plus_one(func):
    return 3

@plus_one
def plus_two(x):
    return x + 2

num = plus_two
print(num) # output = 3 

print 出來 output = 3 ,因為它會等同是 plus_one(plus_two),不管帶什麼都會是 return 3。

裝飾器也能接收參數

因為裝飾器本身是 repeat(Hello) 一樣會把 Hello 丟進去 repeat,只是再多包一層來接收參數。

def repeat(n):
    def decorator(func):
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

@repeat(3)
def Hello():
    print("Hello World!")
    
Hello()
# Hello World!
# Hello World!
# Hello World!

Reference


上一篇
Day-27 | Python - Functions & Closure
下一篇
Day-29 | Database - 什麼時候要使用 Redis ?
系列文
埋藏在後端工程下的地雷與寶藏30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言