O Frozenset é adequado para o armazenamento em cache de dados de entrada simétrica em um ditado de Python?

StackOverflow https://stackoverflow.com/questions/2572899

  •  24-09-2019
  •  | 
  •  

Pergunta

O título mais ou menos diz tudo:

Eu tenho uma função que exige entrada simétrica em dois argumentos, por exemplo, algo como

def f(a1, a2):
    return heavy_stuff(abs(a1 - a2))

Agora, quero apresentar algum método de cache. Seria correto / pitônico / razoavelmente eficiente fazer algo assim:

cache = {}
def g(a1, a2):
    fs =frozenset((tuple(a1), tuple(a2)))
    if fs not in cache:
        cache[fs] = f(a1, a2)
    return cache[fs]

Ou haveria uma maneira melhor?

Editar: A1 e A2 podem ser as fileiras de uma matriz numpy; É por isso que eu os envolvo em uma tupla cada.

Foi útil?

Solução

O Python sempre calcula todos os argumentos que você está passando para uma função e só então chama a função. Em outras palavras, como a maioria dos outros idiomas, o Python é "ansioso" em sua avaliação (a principal exceção hoje é provavelmente Haskell, mas isso não o ajuda ;-).

Então setdefault é um muito Abordagem inadequada para armazenamento em cache! Sempre que você faz

cache.setdefault(akey, f(x, y))

você é primeiro chamando f(x, y), com todo o seu custo computacional, então talvez retirando os resultados desse cálculo no chão; Isso torna o cache totalmente ineficaz.

Em vez disso, sempre faça o seguinte:

akey = whatever(x, y)
if akey not in cache:
    cache[akey] = f(x, y)
return cache[akey]

ou similares - existem alguns outros idiomas possíveis, especialmente se você sabe que f nunca voltará None:

result = cache.get(akey)
if result is None:
    result = cache[akey] = f(x, y)
return result

Quanto à questão secundária do que é apropriado whatever para o cálculo principal, dado que você sabe que f é simétrico, eu acho frozenset provavelmente está ok; embora (se os componentes de x e y são comparáveis, bem como hashable - ou seja, não funcionaria com números complexos), você pode querer considerar

ta1 = tuple(a1)
ta2 = tuple(a2)
if ta1 > ta2: key = ta1, ta2
else: key = ta2, ta1

O desempenho relativo depende do custo de comparação, vs do hash, os itens em a1 e a2. É provável que as diferenças sejam pequenas, de qualquer maneira.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top