記憶(快取)函式返回值 Python 實現

2022-08-21 13:03:15 字數 2719 閱讀 5906

對於經常呼叫的函式,特別是遞迴函式或計算密集的函式,記憶(快取)返回值可以顯著提高效能。而在 python 裡,可以使用字典來完成。

下面這個計算斐波那契數列的函式fib()具有記憶功能,對於計算過的函式引數可以直接給出答案,不必再計算:

fib_memo = {}

def fib(n):

if n < 2: return 1

if not n in fib_memo:

fib_memo[n] = fib(n-1) + fib(n-2)

return fib_memo[n]

我們可以把這個操作包裝成乙個類memory,這個類的物件都具有記憶功能:

class memoize:

"""memoize(fn) - 乙個和 fn 返回值相同的可呼叫物件,但它具有額外的記憶功能。

只適合引數為不可變物件的函式。

"""def __init__(self, fn):

self.fn = fn

self.memo = {}

def __call__(self, *args):

if not args in self.memo:

self.memo[args] = self.fn(*args)

return self.memo[args]

# 原始函式

def fib(n):

print(f'calculating fib()')

if n < 2: return 1

return fib(n-1) + fib(n-2)

# 使用方法

fib = memoize(fib)

執行測試,計算兩次fib(10)

calculating fib(10)

calculating fib(9)

calculating fib(8)

calculating fib(7)

calculating fib(6)

calculating fib(5)

calculating fib(4)

calculating fib(3)

calculating fib(2)

calculating fib(1)

calculating fib(0)

8989

可以看到第二次直接輸出 89,沒有經過計算。

對裝飾器熟悉的程式設計師應該已經想到,這個類可以被當成裝飾器使用。在定義fib()的時候可以直接這樣:

@memoize

def fib(n):

if n < 2: return 1

return fib(n-1) + fib(n-2)

這和之前的**等價,但是更簡潔明瞭。

之前的memory類只適合包裝引數為不可變物件的函式。原因是我們用到了字典作為儲存介質,將引數作為字典的 key;而在 python 中的 dict 只能把不可變物件作為 key 2,例如數字、字串、元組(裡面的元素也得是不可變物件)。所以提高**通用性,我們只能犧牲執行速度,將函式引數序列化為字串再作為 key 來儲存,如下:

class memoize:

"""memoize(fn) - 乙個和 fn 返回值相同的可呼叫物件,但它具有額外的記憶功能。

此時適合所有函式。

"""def __init__(self, fn):

self.fn = fn

self.memo = {}

def __call__(self, *args):

import pickle

s = pickle.dumps(args)

if not s in self.memo:

self.memo[s] = self.fn(*args)

return self.memo[s]

除了這種手工製作的方法,有乙個第三方庫 joblib 能實現同樣的功能,而且效能更好,適用性更廣。因為上文中的方法是快取在記憶體中的,每次都要比較傳入的引數。對於很大的物件作為引數,如 numpy 陣列,這種方法效能很差。而 joblib.memory 模組提供了乙個儲存在硬碟上的memory類,其用法如下:

首先定義快取目錄:

>>> cachedir = 'your_cache_location_directory'
以此快取目錄建立乙個 memory 物件:

>>> from joblib import memory

>>> memory = memory(cachedir, verbose=0)

使用它和使用裝飾器一樣:

>>> @memory.cache

... def f(n):

... print(f'running f()')

... return x

以同樣的引數執行這個函式兩次,只有第一次會真正計算:

>>> print(f(1))

running f(1)

1>>> print(f(1))

1

1

2 3

(本文完)

python 函式返回值

帶有返回值的函式 def add2num a,b c a b return c或者 def add2num a,b return a b在本小節剛開始的時候,說過的 買菸 的例子中,最後兒子給你菸時,你一定是從兒子手中接過來 對麼,程式也是如此,如果乙個函式返回了乙個資料,那麼想要用這個資料,那麼就...

python 函式返回值

python 函式返回值有兩種形式 1 返回乙個值。2 返回多個值。現看看返回乙個值的吧。deffirstvalue a b c a b return cprint firstvalue 1 2 結果 3 再看看返回多個值的 那怎麼可以返回多個值呢,其他的語言一般呼叫函式的話,只能返回乙個值,可能我...

python 函式返回值

函式返回值 return 1 返回乙個值 return result 2 返回多個值 如果返回多個資料,資料之間使用逗號進行分割,那麼返回的是元組型別 return first num,second num,result 3 注意 函式中有return,函式執行到return,函式一定會中斷 如果沒...