iT邦幫忙

2022 iThome 鐵人賽

DAY 6
0
Modern Web

Willisの後端幼幼班系列 第 6

後端幼幼班Day6 Python篇 Decorator(裝飾器)進階

  • 分享至 

  • xImage
  •  

大家好啊~我是Willis,今天要來介紹Decorator(裝飾器)的進階用法唷 ~ (ᗒᗨᗕ)/

使用函數呼叫方式呼叫裝飾器

其實裝飾器只是一種呼叫函數的方式,只是如果用函數的呼叫方式的話會使程式碼過於繁瑣,讓可讀性大大降低,那原本的呼叫方式是怎麼樣呢 ? 一起來看看吧 ~

  • 程式碼 app.py
import random


def odd_fun(fun):
    def wrapper():
        num = fun()
        if (int)(num) % 2 != 0:
            print("{}判斷為奇數".format(num))
        else:
            print("{}判斷為偶數".format(num))
    return wrapper


def random_fun():
    input_num = random.randint(1, 10)
    return input_num


odd_fun(random_fun)()  # 使用函數的呼叫方式
  • 執行結果
8判斷為偶數

5判斷為奇數

今天如果我一次呼叫很多個裝飾器會發生甚麼事呢 ?

複數裝飾器呼叫

使用裝飾器呼叫

  • 程式碼 app.py
def decorator_1(fun):
    def wrappper(*args):
        print("裝飾器1開始")
        fun(*args)
        print("裝飾器1結束")
    return wrappper


def decorator_2(fun):
    def wrappper(*args):
        print("裝飾器2開始")
        fun(*args)
        print("裝飾器2結束")
    return wrappper


def decorator_3(fun):
    def wrappper(*args):
        print("裝飾器3開始")
        fun(*args)
        print("裝飾器3結束")
    return wrappper


@decorator_1
@decorator_2
@decorator_3
def function(*args):
    print("我是函數 傳入參數為:{}".format(*args))


function(123)
  • 執行結果
裝飾器1開始
裝飾器2開始
裝飾器3開始
我是函數 傳入參數為:123
裝飾器3結束
裝飾器2結束
裝飾器1結束

使用函數呼叫

  • 程式碼 app.py
def decorator_1(fun):
    def wrappper(*args):
        print("裝飾器1開始")
        fun(*args)
        print("裝飾器1結束")
    return wrappper


def decorator_2(fun):
    def wrappper(*args):
        print("裝飾器2開始")
        fun(*args)
        print("裝飾器2結束")
    return wrappper


def decorator_3(fun):
    def wrappper(*args):
        print("裝飾器3開始")
        fun(*args)
        print("裝飾器3結束")
    return wrappper


def function(*args):
    print("我是函數 傳入參數為:{}".format(*args))


decorator_1(decorator_2(decorator_3(function)))(123) # 這是甚麼鬼@@ 
  • 執行結果
裝飾器1開始
裝飾器2開始
裝飾器3開始
我是函數 傳入參數為:123
裝飾器3結束
裝飾器2結束
裝飾器1結束

看完原本的呼叫方式後,知道裝飾器的厲害了吧 ~

Decorator Factory (裝飾器工廠-傳遞參數)

裝飾器還有一個厲害的地方,就是它可以傳遞參數。

def 裝飾器工廠名稱(參數名稱)
    def 裝飾器名稱(函數名稱):
        def wrapper():
            ...
        return wrapper
    return 裝飾器名稱
  • 程式碼 app.py
import random


def factory(num):
    def odd_fun(fun):
        def wrapper():
            if (int)(num) % 2 != 0:
                print("{}判斷為奇數".format(num))
            else:
                print("{}判斷為偶數".format(num))
            fun()
        return wrapper
    return odd_fun


@factory(random.randint(1, 10))  # 傳入參數:隨機亂數1 ~ 10
def function():
    print("我是函數")


function()
  • 執行結果
8判斷為偶數
我是函數

Class寫Decorator

除了Fnction能使用裝飾器以外,其實Class也可以使用裝飾器。

無傳遞參數

  • 程式碼 app.py
class Decorateclass():
    def __init__(self, fun):
        self.fun = fun

    def __call__(self, *args, **kwargs):
        print("我是class")
        self.fun()


@Decorateclass
def function():
    print('我是函數')


if __name__ == '__main__':
    function()
  • 執行結果
我是class
我是函數

有傳遞參數

  • 程式碼 app.py
class Decorateclass():
    def __init__(self, num):
        self.num = num

    def __call__(self, fun):
        def wrapper(*args):
            print("我是class 傳入參數為:{}".format(self.num))
            fun()
        return wrapper


@Decorateclass(123)
def function():
    print('我是函數')


if __name__ == '__main__':
    function()
  • 執行結果
我是class 傳入參數為:123
我是函數

參考資料

https://blog.typeart.cc/%E5%BF%AB%E9%80%9F%E7%90%86%E8%A7%A3%E4%B8%A6%E4%BD%BF%E7%94%A8Python%20Decorator/#Class-based-Decorator
https://www.maxlist.xyz/2019/12/07/python-decorator/
https://www.youtube.com/watch?v=F4hWr87ZcSc&ab_channel=%E5%BD%AD%E5%BD%AD%E7%9A%84%E8%AA%B2%E7%A8%8B

結尾

關於Decorator(裝飾器)的介紹就到這裡囉 ~ 大家掰掰 ヽ(✿゚▽゚)ノ


上一篇
後端幼幼班Day5 Python篇 Decorator(裝飾器)基礎
下一篇
後端幼幼班Day7 Python篇 Python開發的好幫手-Pipenv
系列文
Willisの後端幼幼班30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言