簡體   English   中英

memoize 裝飾器中的不可散列類型“dict”錯誤

[英]Unhashable type 'dict' error in memoize decorator

我正在編寫一個 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

這是一個簡單的 function 用於測試我的裝飾器:

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 {}導致正確的 output True

任何幫助,將不勝感激!

這引發異常的原因是,當您在 function 定義中使用**kwargs時,變量kwargs將屬於dict類型。 字典是可變的和不可散列的; 這意味着它們不能用作另一個dict中的鍵或用作set中的元素。 當您執行cache[(args, kwargs)]時,您試圖將 dict kwargs用作 dict cache中鍵的一部分,因此會出現錯誤。 如果您不需要自己實現 memoization function,您可以使用標准庫中functools模塊中的lru_cache function:

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

在這種情況下,args 是(2, 3)並且kwargs是一個空字典(因為您沒有將任何命名的 args 傳遞到您的 function 調用中)。 但是,字典是可變的,不能用作另一個字典中的鍵,因此不是可hashable的。

那么我們從這里到哪里 go 呢? 您可以完全忽略kwargs ,但是當args本身包含字典時,您仍然會遇到問題: slow_func({"key": 1})會導致相同的問題,因為 arg {key: 1}本身就是字典。

在我看來,這似乎是一個非常特定類型的 function 的記憶。 意思是,這樣的包裝不能盲目地應用於任何 function。 arguments 的順序重要嗎? 如果是這樣,僅記住存在的 args 是不夠的。 在 args 周圍放置一些防護欄將使記憶變得可預測且更容易。

這里最簡單的解決方法是只允許kwargs的某些種類或參數或值。 例如:所有 args 和所有kwarg值必須是float s 或int s。

話雖如此,如果您還需要記憶kwargs ,則必須解析字典和args中的任何dict類型,並將格式存儲為某種可散列格式。

想到的一種方法是,您可以將解析的 args 和 kwargs 存儲在自定義 class 中,該自定義 class 實現了__hash__數據方法(更多信息在這里: 制作 python 用戶定義的 ZA2F2ED4F8EBC2CBB4C21A29DC4並將其存儲在您的排序緩存中。 但這一切都取決於你打算如何使用這個memoize裝飾器。

編輯:話雖如此,正如其他人指出的那樣,標准 functools 庫已經包含一些用於緩存的實用方法: https://docs.python.org/3/library/functools.html#functools.cache

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM