裝飾器

  • 有時會修改既有的函式,但不想更改原始程式碼 → 最常見的例子:加入一個除錯的陳述式,來查看有哪些引數被傳入

  • 裝飾器(decorator)是一種函式,它會接收一個函式,並回傳另一個函式

裝飾器(decorator)是一種函式

裝飾器使用的元素:

  • *args 與 **kwargs
  • 內部函式
  • 當成引數的函式

定義裝飾器【使用 document_it() 函式】

document_it() 函式會定義一個裝飾器,它會做以下的工作:

  • 印出 → 函式的名稱,與引數的值
  • 執行函式 → 用引數
  • 印出 → 結果
  • 回傳 → 修改後的函式,以供使用
>>> def document_it(func):                          # document_it() 函式會定義一個裝飾器
        def 函式名稱1(*args, **kwargs):
            print('文字1:', func.__name__)           # 印出 → 函式的名稱
            print('文字2:', args)                    # 印出 → 引數的值
            print('文字3:', kwargs)                  # 印出 → 引數的值
            result = func(*args, **kwargs)
            print('Result:', result)                # 印出 → 結果
            return result
        return 函式名稱1                             # 回傳 → 修改後的函式,以供使用
# 裝飾器不一定要執行任何 func 的程式,但 document_it()會在過程中呼叫 func → 可以取得 func 的結果以及所有額外的東西

>> def document_it(func):                           # 無論將什麼 func 傳給 document_it,都可以得到一個新的函式,裡面有 document_it() 加入的陳述式
    def new_function(*args, **kwargs):
        print('Running function:', func.__name__)
        print('Positional arguments:', args)
        print('Keyword arguments:', kwargs)
        result = func(*args, **kwargs)
        print('Result:', result)
        return result
    return new_function

手動指派裝飾器

>>> def 函式名稱2(引數1, 引數2):
        引數1 + 引數2

>>> 函式名稱2(引數1, 引數2):
        引數1 + 引數2

>>> 函式名稱2 = document_it(函式名稱1)
>>> 函式名稱3(引數1, 引數2)
文字1: 函式名稱1
文字2: (引數1, 引數2)
文字3: {}
result: 引數1 + 引數2
引數1 + 引數2
>>> def add_ints(a, b):
    return a + b

>>> add_ints(3, 5)
8

>>> cooler_add_ints = document_it(add_ints)
>>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8

取代手動指派裝飾器【使用 @decorator_name】

可以在想要裝飾的函式前添加 @decorator_name,來取代上述的手動指派裝飾器

>>> @document_it
    def 串列名稱2(引數1, 引數2):
        return 引數1 + 引數2

>>> 串列名稱2(引數1, 引數2)
文字1: 函式名稱1
文字2: (引數1, 引數2)
文字3: {}
result: 引數1 + 引數2
引數1 + 引數2

可以在想要裝飾的函式前添加 @decorator_name,來取代上述的手動指派裝飾器

# 手動應用裝飾器
>>> def add_ints(a,b):
    return a + b

>>> add_ints(3, 5)
8
>>> cooler_add_ints = document_it(add_ints)
>>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8

# 可以在想要裝飾的函式前添加 @decorator_name,來取代上述的手動指派裝飾器
>>> @document_it
    def add_ints(a,b):
        return a + b

>>> add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8

同一個函式可以有兩個以上的裝飾器

編寫另一個裝飾器,稱為 square_it(),它會將結果平方

>>> def 函式名稱1(func):
        def 函式名稱2(*args, **kwargs):
            result = func(*args, **kwargs)
            eturn result * result
        return 函式名稱
>>> def square_it(func):
        def new_function(*args, **kwargs):
            result = func(*args, **kwargs)
            return result * result
        return new_function

裝飾器執行順序不同,但最終結果都一樣

完整執行過程

>>> def document_it(func):                          # document_it() 函式會定義一個裝飾器
        def 函式名稱1(*args, **kwargs):
            print('文字1:', func.__name__)           # 印出 → 函式的名稱
            print('文字2:', args)                    # 印出 → 引數的值
            print('文字3:', kwargs)                  # 印出 → 引數的值
            result = func(*args, **kwargs)
            print('Result:', result)                # 印出 → 結果
            return result
        return 函式名稱1                             # 回傳 → 修改後的函式,以供使用


# 手動應用裝飾器
>>> def 函式名稱2(引數1, 引數2):
        引數1 + 引數2

>>> 函式名稱2(引數1, 引數2):
        引數1 + 引數2


# 無論將什麼 func 傳給 document_it,都可以得到一個新的函式,裡面有 document_it() 加入的陳述式
>>> 函式名稱3 = document_it(函式名稱2)

# 裝飾器不一定要執行任何 func 的程式
# 但 document_it() 會在過程中呼叫 func,讓你可以取得 func 的結果以及額外的東西
>>> 函式名稱3(引數1, 引數2)
文字1: 函式名稱1
文字2: (引數1, 引數2)
文字3: {}
result: 引數1 + 引數2
引數1 + 引數2


# 可以在想要裝飾的函式前添加 @decorator_name,來取代上述的手動指派裝飾器
>>> @document_it
    def 串列名稱2(引數1, 引數2):
        return 引數1 + 引數2

>>> 串列名稱2(引數1, 引數2)
文字1: 函式名稱1
文字2: (引數1, 引數2)
文字3: {}
result: 引數1 + 引數2
引數1 + 引數2


# 同一個函式可以有兩個以上的裝飾器。編寫另一個裝飾器,稱為 square_it(),它會將結果平方
>>> def 函式名稱4(func):
        def 函式名稱1(*args, **kwargs):
            result = func(*args, **kwargs)
            return result * result
        return 函式名稱1

# 最靠近函式的裝飾器(在 def 正上方的)會先執行 → 接著是它上面的那個
# 無論順序為何,最終的結果都一樣的,但可以看到過程中有不同的步驟
# 方法一
>>> @document_it
    @函式名稱4                                # @函式名稱4 先執行 → 再執行 @document_it
    def 函式名稱2(引數1, 引數2):
        return 引數1 + 引數2

>>> 函式名稱2(引數1, 引數2)
文字1: 函式名稱1
文字2: (引數1, 引數2)
文字3: {}
result: (引數1 + 引數2)*(引數1 + 引數2)
(引數1 + 引數2)*(引數1 + 引數2)


# 方法二
>>> @函式名稱4
    @document_it                                # @document_it 先執行 → 再執行 @函式名稱4
    def 函式名稱2(引數1, 引數2):
        return 引數1 + 引數2

>>> 函式名稱2(引數1, 引數2)
文字1: 函式名稱2
文字2: (引數1, 引數2)
文字3: {}
result: 引數1 + 引數2
(引數1 + 引數2)*(引數1 + 引數2)
# document_it()函式,定義一個裝飾器 @document_it
>>> def document_it(func):
    def new_function(*args, **kwargs):
        print('Running function:', func.__name__)
        print('Positional arguments:', args)
        print('Keyword arguments:', kwargs)
        result = func(*args, **kwargs)
        print('Result:', result)
        return result
    return new_function


# 手動應用裝飾器
>>> def add_ints(a, b):
    return a + b

>>> add_ints(3, 5)
8
>>> cooler_add_ints = document_it(add_ints)
>>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8


# 在想要裝飾的函式前添加 @decorator_name,來取代上述的「手動指派裝飾器」
>>> def add_ints(a,b):
    return a + b

>>> add_ints(3, 5)
8
>>> cooler_add_ints = document_it(add_ints)
>>> cooler_add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8
8


# 同一個函式可以有兩個以上的裝飾器
# 編寫另一個裝飾器,稱為 square_it(),它會將結果平方
>>> def square_it(func):
    def new_function(*args, **kwargs):
        result = func(*args, **kwargs)
        return result * result
    return new_function


# 最靠近函式的裝飾器(在 def 正上方的)會最先執行 → 接著是它上面的那一個
# 無論裝飾器的順序為何,最終的結果都一樣的,但可以看到過程中有不同的步驟
# 先執行 @aquare_it → @document_it
>>> @document_it
    @square_it
    def add_ints(a, b):
        return a + b

>>> add_ints(3, 5)
Running function: new_function
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 64                                   # 先執行 @aquare_it → @document_it
64

# 先執行 @document_it → @aquare_it
>> @square_it
   @document_it
   def add_ints(a,b):
       return a + b

>>> add_ints(3, 5)
Running function: add_ints
Positional arguments: (3, 5)
Keyword arguments: {}
Result: 8                                     # 先執行 @document_it → @aquare_it
64
64

results matching ""

    No results matching ""