我正在寫一個 memoize 裝飾器,但是在一個簡單的例子上嘗試它時,我得到了一個不可散列的型別“dict”錯誤。這是我的代碼:
def memoize(func):
"""Store the results of the decorated function for fast lookup
"""
# Store results in a dict that maps arguments to results
cache = {}
# Define the wrapper function to return
def wrapper(*args, **kwargs):
# If these arguments haven't been seen before,
if (args, kwargs) not in cache:
# Call func() and store the result.
cache[(args, kwargs)] = func(*args, **kwargs)
return cache[(args, kwargs)]
return wrapper
這是為測驗我的裝飾器而創建的一個簡單函式:
import time
@memoize
def slow_func(a, b):
print("Sleeping...")
time.sleep(5)
return a b
slow_func(2, 7)
我最終遇到了這個錯誤:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
~\AppData\Local\Temp/ipykernel_17888/3627587563.py in <module>
----> 1 slow_func(2, 7)
~\AppData\Local\Temp/ipykernel_17888/52581778.py in wrapper(*args, **kwargs)
7 def wrapper(*args, **kwargs):
8 # If these arguments haven't been seen before,
----> 9 if (args, kwargs) not in cache:
10 # Call func() and store the result.
11 cache[(args, kwargs)] = func(*args, **kwargs)
TypeError: unhashable type: 'dict'
我進行了測驗,以防我的 Python 正常作業:
(2, 3) not in {}這導致了正確的輸出True。
任何幫助,將不勝感激!
uj5u.com熱心網友回復:
這引發例外的原因是,當您**kwargs在函式定義中使用時,變數kwargs的型別為dict。字典是可變的和不可散列的;這意味著它們不能用作另一個中的鍵dict或用作set. 當您這樣做時cache[(args, kwargs)],您試圖將 dictkwargs用作dict中鍵的一部分cache,因此會出現錯誤。如果不需要自己實作備忘功能,可以使用標準庫中模塊的lru_cache功能functools:
import functools, time
@functools.lru_cache
def slow_func(a, b):
print("Sleeping...")
time.sleep(5)
return a b
t1 = time.monotonic()
slow_func(2, 7)
slow_func(2, 7)
t2 = time.monotonic()
print("Total time:", t2-t1)
印刷:
python t.py
Sleeping...
Total time: 5.005460884000058
uj5u.com熱心網友回復:
在這種情況下, args are(2, 3)和 the kwargsis 是一個空字典(因為您沒有將任何命名的 args 傳遞到您的函式呼叫中)。但是,字典是可變的,不能用作另一個字典中的鍵,因此不是hashable.
那么,我們該何去何從?您可以kwargs完全忽略,但是當args它本身包含字典時仍然會遇到問題:
slow_func({"key": 1})會導致相同的問題,因為 arg{key: 1}本身就是字典。
在我看來,這是一種非常特定型別的功能的記憶。意思是,像這樣的包裝器不能盲目地應用于任何函式。引數的順序重要嗎?如果是這樣,僅僅記住存在的 args 是不夠的。在 args 周圍放置一些護欄將使記憶變得可預測且更容易。
這里最簡單的解決方法是只允許kwargs. 例如:所有引數和所有kwarg值都必須是floats 或ints。
話雖如此,如果您還需要記憶,則必須kwargs決議字典和任何dict型別,args并以某種可散列格式存盤格式。
想到的一種方法是,您可以將決議的 args 和 kwargs 存盤在實作__hash__data 方法的自定義類中(更多相關資訊:使 python 用戶定義的類可排序、可散列),然后將其存盤在快取中。但同樣,這一切都取決于您打算如何memoize使用此裝飾器。
編輯:話雖如此,正如其他人指出的那樣,標準的 functools 庫包含一些已經用于快取的實用方法:https : //docs.python.org/3/library/functools.html#functools.cache
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/394108.html
