我想缓存一个以列表作为参数的函数,但是当我尝试使用functools.lru_cache
装饰器时,它会失败并显示TypeError: unhashable type: 'list'
。
import functools
@functools.lru_cache()
def example_func(lst):
return sum(lst) + max(lst) + min(lst)
print(example_func([1, 2]))
答案 0 :(得分:7)
它不应该引发错误,而是在装饰器中转换为可哈希的形式,而用户甚至不知道它。您可以通过如下装饰功能来解决此问题:
#Custom Decorator function
def listToTuple(function):
def wrapper(*args):
args = [tuple(x) if type(x) == list else x for x in args]
result = function(*args)
result = tuple(result) if type(result) == list else result
return result
return wrapper
#your cached function
@listToTuple
@lru_cache(maxsize=cacheMaxSize)
def checkIfAdminAcquired(self, adminId) -> list:
query = "SELECT id FROM public.admins WHERE id IN ({}) and
confirmed_at IS NOT NULL"
response = self.handleQuery(query, "int", adminId)
return response
您可能要在lru_cache之后使用另一个修饰符,以确保函数的输出不是元组,而是列表,因为现在它将返回元组。
答案 1 :(得分:6)
此操作失败,因为列表不可用。这将使Python很难知道缓存了哪些值。解决这个问题的一种方法是将列表转换为元组,然后再将它们传递给缓存函数:因为元组是不可变的,可以缓存,所以它们可以被缓存。
答案 2 :(得分:0)
正如当前答案所建议的那样,有时参数可以采用简单的可哈希类型,也可以采用复杂的不可哈希类型,而无需直接转换为可哈希类型。在这种情况下,仍然可能希望有一个用于(可能是更常见的)可哈希类型的情况的缓存,而无需使用缓存或在不可哈希的情况下出错-只需调用底层函数即可。
这将忽略该错误,并且通常可用于任何可哈希类型:
import functools
def ignore_unhashable(func):
uncached = func.__wrapped__
attributes = functools.WRAPPER_ASSIGNMENTS + ('cache_info', 'cache_clear')
@functools.wraps(func, assigned=attributes)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except TypeError as error:
if 'unhashable type' in str(error):
return uncached(*args, **kwargs)
raise
wrapper.__uncached__ = uncached
return wrapper
使用和测试:
@ignore_unhashable
@functools.lru_cache()
def example_func(lst):
return sum(lst) + max(lst) + min(lst)
example_func([1, 2]) # 6
example_func.cache_info()
# CacheInfo(hits=0, misses=0, maxsize=128, currsize=0)
example_func((1, 2)) # 6
example_func.cache_info()
# CacheInfo(hits=0, misses=1, maxsize=128, currsize=1)
example_func((1, 2)) # 6
example_func.cache_info()
# CacheInfo(hits=1, misses=1, maxsize=128, currsize=1)
花点时间绕过它,但是example_func.__wrapped__
是lru_cache的版本,example_func.__uncached__
是原始版本。