Contents

裝飾器(Decorator)

Contents

裝飾器為python的語法糖(syntax candy),旨在簡化函式之間的相互呼叫,能透過簡單的@就呼叫出事先編寫好的函式。

使用順序上則是遵循遞迴的(recursive)構造,會先將函式丟入離最近的裝飾器中,再將整體丟入更上層的裝飾器中。

裝飾器一旦被寫下,無論是否呼叫被裝飾的函式,裝飾器都會被執行,若不想執行裝飾器,則裝飾器最外層只能留下retuen指令1

Tip
簡易的理解方式:擁有裝飾器的函式,會先執行裝飾器的內容,再執行原先函式。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def fun2(v):
    def decorator(fun):
        print('This is not a decorator.')
        return fun
    decorator(fun2)
    #在語法糖中被@取代
    print(v)

#以上等價於

def decorator(fun):
    print('This is a decorator.')
    return fun

@decorator
def fun3(v):
    print(v)


if __name__ == "__main__":
	f1 = fun2(5)
	#>>>'This is not a decorator.'
	#>>>5
	f2 = fun3(5)
	#>>>'This is a decorator.'
	#>>>5

此外,裝飾器本身也能帶有參數。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def decorator(text):
    def decorator2(fun):
        print('This is another decorator.')
        return fun
    print('This is a decorator.')
    print(text)
    return decorator2


@decorator('Hello')
def fun2(v):
    print(v)


if __name__ == "__main__":
    fun2(1)
    #>>>This is a decorator.
	#>>>Hello
	#>>>This is another decorator.
	#>>>1

若裝飾器需要裝飾多個函式,每個函式間的參數皆不同,則需要使用*args**kwargs

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def decorator(fun):
    def decorator2(*args, **kwargs):
        print('This is a decorator.')
        return fun(*args, **kwargs)
    return decorator2


@decorator
def fun2(v):
    print(v)


@decorator
def fun3(a, b, c):
    print(a, b, c)

類別也能當作裝飾器使用2


Reference