def fibonacci(n):
if n in (0, 1):
return n
return fibonacci(n-1) + fibonacci(n-2)
定義下面的 decorator
class memoized(object):
def __init__(self, func):
self.func = func
self.cache = {}
def __call__(self, *args):
try:
return self.cache[args]
except KeyError:
self.cache[args] = value = self.func(*args)
return value
使用方法很簡單在函式定義上一行加上
@memoized 即可,之後呼叫 fibonacci(n) 時,
程式會先檢查快取中有沒有這個值,如果有就傳回,
如果沒有就呼叫 fibonacci(n),之後把計算得到值存入快取,再傳回。
之後如果我們想要替任何一個函式加上快取,只要在函式定義上一行加上
@memoized,而不需要更動函式實作,是不是很方便呢?
def compute(x):
return x**3 - 1
此函式的輸入是一個數字,如果輸入想改成數字串列的話,
一般的想法是直接更改函式實作,可是如果有很多類似函式,
一個一個改就嫌累贅,這時 decorator 就派上用場了,定義
def elementwise(fn):
def newfn(arg):
if hasattr(arg,'__getitem__'): # is a sequence
return type(arg)(map(fn, arg))
else:
return fn(arg)
return newfn
在 compute() 定義上一行加上 @elementwise,
函式就可以接受數字串列了。
之後呼叫 compute(x) 時,函式會判斷輸入變數是不是串列,
如果不是的話,就直接傳回 compute(x),如果是的話,
會產生一個新的串列,其元素是 compute(y),y 是 x 其中一個元素。
(如果對 map 不熟的話,可以參考
之前的部落格,其實不用 map,改用 list comprehension 也可以。)
由於 map 的傳回值型態是 list,為了讓傳回值型態跟輸入型態一致,
所以 map 前要加上 type(arg) 轉型。
註: 第一個例子來自 Python Decorator Library 的第三個範例,而第二個例子來自 Charming Python 的 Listing 12。

No comments:
Post a Comment