Acabei de iniciar o Python e não tenho ideia do que é memorização e como usá-la. Além disso, posso ter um exemplo simplificado?
python
memoization
blur959
fonte
fonte
Respostas:
Memorização refere-se efetivamente aos resultados de memorização ("memorização" → "memorando" → a ser lembrado) de chamadas de método com base nas entradas do método e, em seguida, retornando o resultado lembrado em vez de computá-lo novamente. Você pode pensar nisso como um cache para obter resultados do método. Para mais detalhes, consulte a página 387 para a definição em Introdução aos algoritmos (3e), Cormen et al.
Um exemplo simples para calcular fatoriais usando memoização em Python seria algo como isto:
Você pode ficar mais complicado e encapsular o processo de memorização em uma classe:
Então:
Um recurso conhecido como " decoradores " foi adicionado no Python 2.4, que permite que você simplesmente escreva o seguinte para realizar a mesma coisa:
A Python Decorator Library possui um decorador semelhante chamado
memoized
que é um pouco mais robusto do que aMemoize
classe mostrada aqui.fonte
factorial_memo
, porque ofactorial
interiordef factorial
ainda chama o antigo desmembrarfactorial
.if k not in factorial_memo:
, que lê melhor queif not k in factorial_memo:
.args
é uma tupla.def some_function(*args)
faz args uma tupla.Novo no Python 3.2 é
functools.lru_cache
. Por padrão, ele armazena em cache apenas as 128 chamadas usadas mais recentemente, mas você pode configurámaxsize
-loNone
para indicar que o cache nunca deve expirar:Esta função por si só é muito lenta, tente
fib(36)
e você terá que esperar cerca de dez segundos.A adição de
lru_cache
anotação garante que, se a função tiver sido chamada recentemente para um valor específico, ela não recalculará esse valor, mas usará um resultado anterior em cache. Nesse caso, isso leva a uma tremenda melhoria de velocidade, enquanto o código não é confuso com os detalhes do cache.fonte
fib
for chamado, será necessário retornar ao caso base antes que a memorização possa acontecer. Portanto, seu comportamento é praticamente o esperado.As outras respostas cobrem o que está muito bem. Eu não estou repetindo isso. Apenas alguns pontos que podem ser úteis para você.
Normalmente, a memória é uma operação que você pode aplicar em qualquer função que calcule algo (caro) e retorne um valor. Por esse motivo, é frequentemente implementado como um decorador . A implementação é simples e seria algo como isto
ou expresso como um decorador
fonte
A memorização é manter os resultados de cálculos caros e retornar o resultado em cache, em vez de recalculá-lo continuamente.
Aqui está um exemplo:
Uma descrição mais completa pode ser encontrada na entrada da Wikipedia sobre memorização .
fonte
if input not in self.cache
eself.cache[input]
(has_key
é obsoleta desde ... no início da série 2.x, se não for 2.0.self.cache(index)
Nunca foi correta IIRC.)Não vamos esquecer a
hasattr
função embutida, para quem deseja criar manualmente. Dessa forma, você pode manter o cache de mem dentro da definição da função (em oposição a um global).fonte
Eu achei isso extremamente útil
fonte
functools.wraps
.memo
para que a memória seja liberada?A memorização consiste basicamente em salvar os resultados de operações anteriores feitas com algoritmos recursivos, a fim de reduzir a necessidade de percorrer a árvore de recursão se o mesmo cálculo for necessário posteriormente.
consulte http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/
Exemplo de memorização de Fibonacci em Python:
fonte
Memoização é a conversão de funções em estruturas de dados. Normalmente, a conversão é realizada de forma incremental e lenta (sob demanda de um determinado elemento de domínio - ou "chave"). Em linguagens funcionais preguiçosas, essa conversão preguiçosa pode ocorrer automaticamente e, portanto, a memorização pode ser implementada sem efeitos colaterais (explícitos).
fonte
Bem, eu deveria responder a primeira parte primeiro: o que é memorização?
É apenas um método para trocar memória por tempo. Pense na tabela de multiplicação .
Usar objeto mutável como valor padrão no Python geralmente é considerado ruim. Mas se usá-lo com sabedoria, pode ser realmente útil implementar a
memoization
.Aqui está um exemplo adaptado de http://docs.python.org/2/faq/design.html#why-are-default-values-shared-between-objects
Usando um mutável
dict
na definição da função, os resultados intermediários calculados podem ser armazenados em cache (por exemplo, ao calcularfactorial(10)
após o cálculofactorial(9)
, podemos reutilizar todos os resultados intermediários)fonte
Aqui está uma solução que funcionará com argumentos de lista ou tipo de ditado sem reclamar:
Observe que essa abordagem pode ser estendida naturalmente a qualquer objeto, implementando sua própria função de hash como um caso especial no handle_item. Por exemplo, para fazer essa abordagem funcionar para uma função que aceita um conjunto como argumento de entrada, você pode adicionar ao handle_item:
fonte
list
argumento de[1, 2, 3]
pode erroneamente ser considerado o mesmo que umset
argumento diferente com um valor de{1, 2, 3}
. Além disso, os conjuntos não são ordenados como dicionários, portanto, também precisam sersorted()
. Observe também que um argumento recursivo da estrutura de dados causaria um loop infinito.list
esset
são "tuplaizados" na mesma coisa e, portanto, tornam-se indistinguíveis um do outro. O código de exemplo para adicionar suportesets
descrito em sua atualização mais recente não evita que eu tenha medo. Isso pode ser facilmente visto passando separadamente[1,2,3]
e{1,2,3}
como argumento para uma função de teste "memoize" d e ver se é chamado duas vezes, como deveria ser ou não.list
s edict
s porque é possível quelist
a tenha exatamente a mesma coisa que resultou da chamadamake_tuple(sorted(x.items()))
de um dicionário. Uma solução simples para os dois casos seria incluir otype()
valor of na tupla gerada. Posso pensar em uma maneira ainda mais simples de lidar especificamente comset
s, mas isso não generaliza.Solução que funciona com argumentos posicionais e de palavras-chave, independentemente da ordem em que os argumentos das palavras-chave foram transmitidos (usando inspect.getargspec ):
Pergunta semelhante: Identificar funções varargs equivalentes exige memorização em Python
fonte
fonte
if n not in cache
vez disso. usandocache.keys
criaria uma lista desnecessária em python 2Só queria acrescentar às respostas já fornecidas, a biblioteca decoradora Python tem algumas implementações simples, mas úteis, que também podem memorizar "tipos laváveis", ao contrário
functools.lru_cache
.fonte