2021年12月12日 星期日

Python:簡介 function decorator

Function decorator 有兩個特性:

  1. 它可以用來替代 decorated 函數
  2. Decorator 在讀取模組時便執行

以下為一個例子:

def deco(func):
    print("Init")
    def wrapper():
        print("Before")
        func()
        print("After")
    return wrapper

@deco
def hello():
    print("Hello!")

print("Ya!")
hello()
# Results:
# Init
# Ya!
# Before
# Hello!
# After

從以上的例子可看出我們把 hello 函數當成參數丟給 deco 函數,也就是類似 deco(hello) 的意思。而 deco 函數在模組的讀取階段就已經執行了,因此會先印出 Init,之後才印出剩下的文字。

例子:函數計時器

這裡用一個函數計時器的例子來展示 function decorator 的用途:

import time

def clock(func):
    def clocked(*args):
        t0 = time.perf_counter()
        result = func(*args)
        elapsed = time.perf_counter() - t0
        print('%0.8fs' % elapsed) # 0.10066449s
        return result
    return clocked

@clock
def snooze(seconds):
    time.sleep(seconds)

snooze(0.1)

Standard library 中的 decorator 例子

首先是 functools.lru_cache,它可以用來記錄之前得到的結果。以下為一個例子:
import functools

@functools.lru_cache()
def fib(n):
    if n < 2:
        return n
    return fib(n-2) * fib(n-1)

t0 = time.perf_counter()
fib(30)
elapsed = time.perf_counter() - t0
print('%0.8fs' % elapsed)
# With lru_cache: 0.00010853s
# Without lru_cache: 0.32648241s

另一個例子是 functools.singledispatch,它可以用來做 generic programming。細節請參考資料 [1]。

參考資料

[1] PEP 443 -- Single-dispatch generic functions

沒有留言:

張貼留言