Python3传递列表以使用functools.lru_cache运行

时间:2018-03-10 15:31:46

标签: python python-3.x functools

我想缓存一个以列表作为参数的函数,但是当我尝试使用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]))

3 个答案:

答案 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__是原始版本。