Je viens de commencer Python et je n'ai aucune idée de ce qu'est la mémorisation et comment l'utiliser. De plus, puis-je avoir un exemple simplifié?
python
memoization
blur959
la source
la source
Réponses:
La mémorisation se réfère effectivement à la mémorisation ("mémorisation" → "mémorandum" → à mémoriser) des résultats d'appels de méthode en fonction des entrées de méthode, puis au retour du résultat mémorisé plutôt que de calculer à nouveau le résultat. Vous pouvez le considérer comme un cache pour les résultats de la méthode. Pour plus de détails, voir page 387 pour la définition dans Introduction To Algorithms (3e), Cormen et al.
Un exemple simple de calcul de factorielles utilisant la mémorisation en Python serait quelque chose comme ceci:
Vous pouvez devenir plus compliqué et encapsuler le processus de mémorisation dans une classe:
Alors:
Une fonctionnalité connue sous le nom de " décorateurs " a été ajoutée dans Python 2.4 qui vous permet maintenant d'écrire simplement ce qui suit pour accomplir la même chose:
La bibliothèque Python Decorator possède un décorateur similaire appelé
memoized
qui est légèrement plus robuste que laMemoize
classe présentée ici.la source
factorial_memo
, car l'factorial
intérieurdef factorial
appelle toujours l'ancien unmemizefactorial
.if k not in factorial_memo:
, qui lit mieux queif not k in factorial_memo:
.args
c'est un tuple.def some_function(*args)
fait d'args un tuple.Nouveau dans Python 3.2 est
functools.lru_cache
. Par défaut, il met en cache uniquement les 128 plus récemment des appels utilisés, mais vous pouvez définir l'maxsize
àNone
indiquer que le cache ne doit jamais expirer:Cette fonction en elle-même est très lente, essayez
fib(36)
et vous devrez attendre une dizaine de secondes.L'ajout d'
lru_cache
annotations garantit que si la fonction a été appelée récemment pour une valeur particulière, elle ne recalculera pas cette valeur, mais utilisera un résultat précédent mis en cache. Dans ce cas, cela conduit à une amélioration considérable de la vitesse, tandis que le code n'est pas encombré par les détails de la mise en cache.la source
fib
, elle devra se reproduire dans le cas de base avant que la mémorisation ne puisse avoir lieu. Donc, votre comportement est à peu près attendu.Les autres réponses couvrent assez bien ce que c'est. Je ne répète pas ça. Juste quelques points qui pourraient vous être utiles.
Habituellement, la mémoisation est une opération que vous pouvez appliquer à n'importe quelle fonction qui calcule quelque chose (cher) et renvoie une valeur. Pour cette raison, il est souvent mis en œuvre en tant que décorateur . L'implémentation est simple et ce serait quelque chose comme ça
ou exprimé en tant que décorateur
la source
La mémorisation consiste à conserver les résultats de calculs coûteux et à renvoyer le résultat mis en cache plutôt que de le recalculer en continu.
Voici un exemple:
Une description plus complète peut être trouvée dans l' entrée wikipedia sur la mémorisation .
la source
if input not in self.cache
etself.cache[input]
(has_key
est obsolète depuis ... au début de la série 2.x, sinon 2.0self.cache(index)
. N'a jamais été correct. IIRC)N'oublions pas la
hasattr
fonction intégrée, pour ceux qui veulent fabriquer à la main. De cette façon, vous pouvez conserver le cache mem dans la définition de la fonction (par opposition à un global).la source
J'ai trouvé cela extrêmement utile
la source
functools.wraps
.memo
afin que la mémoire soit libérée?La mémorisation consiste essentiellement à sauvegarder les résultats des opérations passées effectuées avec des algorithmes récursifs afin de réduire la nécessité de parcourir l'arbre de récursivité si le même calcul est requis à un stade ultérieur.
voir http://scriptbucket.wordpress.com/2012/12/11/introduction-to-memoization/
Exemple de mémorisation de Fibonacci en Python:
la source
La mémorisation est la conversion de fonctions en structures de données. Habituellement, on veut que la conversion se fasse de manière incrémentielle et paresseuse (à la demande d'un élément de domaine donné - ou "clé"). Dans les langages fonctionnels paresseux, cette conversion paresseuse peut se produire automatiquement, et ainsi la mémorisation peut être implémentée sans effets secondaires (explicites).
la source
Eh bien, je devrais d'abord répondre à la première partie: qu'est-ce que la mémorisation?
C'est juste une méthode pour échanger de la mémoire contre du temps. Pensez à la table de multiplication .
L'utilisation d'un objet mutable comme valeur par défaut dans Python est généralement considérée comme mauvaise. Mais si vous l'utilisez à bon escient, il peut être utile d'implémenter a
memoization
.Voici un exemple adapté de http://docs.python.org/2/faq/design.html#why-are-default-values-shared-between-objects
En utilisant un mutable
dict
dans la définition de la fonction, les résultats intermédiaires calculés peuvent être mis en cache (par exemple lors du calculfactorial(10)
après calculfactorial(9)
, nous pouvons réutiliser tous les résultats intermédiaires)la source
Voici une solution qui fonctionnera avec des arguments de type liste ou dict sans pleurnicher:
Notez que cette approche peut être naturellement étendue à n'importe quel objet en implémentant votre propre fonction de hachage comme cas spécial dans handle_item. Par exemple, pour que cette approche fonctionne pour une fonction qui prend un ensemble comme argument d'entrée, vous pouvez ajouter à handle_item:
la source
list
argument de[1, 2, 3]
peut à tort être considéré comme unset
argument différent avec une valeur de{1, 2, 3}
. De plus, les ensembles ne sont pas ordonnés comme les dictionnaires, ils devraient donc également l'êtresorted()
. Notez également qu'un argument de structure de données récursive provoquerait une boucle infinie.list
s etset
s sont «tupleisés» dans la même chose et deviennent donc indiscernables l'un de l'autre. L'exemple de code pour ajouter le support poursets
décrit dans votre dernière mise à jour n'évite pas que j'en ai peur. Cela peut facilement être vu en passant séparément[1,2,3]
et{1,2,3}
en tant qu'argument à une fonction de test d "mémoize" et en voyant si elle est appelée deux fois, comme il se doit, ou non.list
s etdict
s car il est possible que alist
contienne exactement la même chose qui résulte de l'appelmake_tuple(sorted(x.items()))
à un dictionnaire. Une solution simple pour les deux cas serait d'inclure latype()
valeur dans le tuple généré. Je peux penser à un moyen encore plus simple de gérer spécifiquement lesset
s, mais cela ne se généralise pas.Solution qui fonctionne avec les arguments de position et de mot-clé indépendamment de l'ordre dans lequel les arguments de mot-clé ont été passés (en utilisant inspect.getargspec ):
Question similaire: L' identification de la fonction varargs équivalente appelle la mémorisation en Python
la source
la source
if n not in cache
place. l'utilisationcache.keys
créerait une liste inutile en python 2Je voulais juste ajouter aux réponses déjà fournies, la bibliothèque de décorateur Python a quelques implémentations simples mais utiles qui peuvent également mémoriser des "types non partageables", contrairement à
functools.lru_cache
.la source