Ich habe gerade mit Python angefangen und habe keine Ahnung, was Memoisierung ist und wie man es verwendet. Kann ich auch ein vereinfachtes Beispiel haben?
Antworten
Zu viele Anzeigen?Memoisierung bedeutet, dass die Ergebnisse von Methodenaufrufen auf der Grundlage der Methodeneingaben gespeichert werden ("Memoisierung", "Memorandum") und dann das gespeicherte Ergebnis zurückgegeben wird, anstatt das Ergebnis erneut zu berechnen. Man kann es sich als einen Cache für Methodenergebnisse vorstellen. Weitere Einzelheiten finden Sie auf Seite 387, wo die Definition in Einführung in Algorithmen (3e), Cormen et al.
Ein einfaches Beispiel für die Berechnung von Fakultäten mit Hilfe von Memoisierung in Python wäre etwa so:
factorial_memo = {}
def factorial(k):
if k < 2: return 1
if k not in factorial_memo:
factorial_memo[k] = k * factorial(k-1)
return factorial_memo[k]
Sie können auch komplizierter vorgehen und den Memoisierungsprozess in einer Klasse kapseln:
class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
#Warning: You may wish to do a deepcopy here if returning objects
return self.memo[args]
Dann:
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
factorial = Memoize(factorial)
Ein Merkmal, das als " Dekorateure " wurde in Python 2.4 hinzugefügt, so dass Sie jetzt einfach das Folgende schreiben können, um dasselbe zu erreichen:
@Memoize
def factorial(k):
if k < 2: return 1
return k * factorial(k - 1)
En Python-Dekorator-Bibliothek hat einen ähnlichen Dekorator namens memoized
die etwas robuster ist als die Memoize
Klasse, die hier gezeigt wird.
functools.cache
Dekorateur:
Mit Python 3.9 wurde eine neue Funktion functools.cache
. Es speichert das Ergebnis einer Funktion, die mit einem bestimmten Satz von Argumenten aufgerufen wurde, im Speicher, was eine Memoisierung darstellt. Es ist einfach zu benutzen:
import functools
import time
@functools.cache
def calculate_double(num):
time.sleep(1) # sleep for 1 second to simulate a slow calculation
return num * 2
Das erste Mal, dass Sie anrufen caculate_double(5)
dauert es eine Sekunde und gibt 10 zurück. Wenn Sie die Funktion ein zweites Mal mit demselben Argument aufrufen calculate_double(5)
wird sofort 10 zurückgegeben.
Hinzufügen der cache
Dekorator stellt sicher, dass die Funktion, wenn sie kürzlich für einen bestimmten Wert aufgerufen wurde, diesen Wert nicht neu berechnet, sondern ein zwischengespeichertes früheres Ergebnis verwendet. In diesem Fall führt dies zu einer enormen Geschwindigkeitssteigerung, während der Code nicht mit den Details der Zwischenspeicherung überladen ist.
( Editer (Das vorherige Beispiel berechnete eine Fibonacci-Zahl mit Hilfe von Rekursion, aber ich habe das Beispiel geändert, um Verwirrung zu vermeiden, daher die alten Kommentare).
functools.lru_cache
Dekorateur:
Wenn Sie ältere Versionen von Python unterstützen müssen, functools.lru_cache
funktioniert in Python 3.2+. Standardmäßig werden nur die 128 zuletzt verwendeten Aufrufe zwischengespeichert, aber Sie können die maxsize
a None
um anzugeben, dass der Cache nie ablaufen soll:
@functools.lru_cache(maxsize=None)
def calculate_double(num):
# etc
Die anderen Antworten beschreiben recht gut, worum es sich handelt. Ich werde das nicht wiederholen. Nur einige Punkte, die für Sie nützlich sein könnten.
Normalerweise ist die Memoisierung eine Operation, die Sie auf jede Funktion anwenden können, die etwas (Teures) berechnet und einen Wert zurückgibt. Aus diesem Grund wird sie oft als eine Tapezierer . Die Umsetzung ist einfach und würde etwa so aussehen
memoised_function = memoise(actual_function)
oder als Dekorator ausgedrückt
@memoise
def actual_function(arg1, arg2):
#body
Ich habe dies als äußerst nützlich empfunden
from functools import wraps
def memoize(function):
memo = {}
@wraps(function)
def wrapper(*args):
# add the new key to dict if it doesn't exist already
if args not in memo:
memo[args] = function(*args)
return memo[args]
return wrapper
@memoize
def fibonacci(n):
if n < 2: return n
return fibonacci(n - 1) + fibonacci(n - 2)
fibonacci(25)
Nicht zu vergessen sind die eingebauten hasattr
Funktion, für diejenigen, die handwerklich arbeiten wollen. Auf diese Weise können Sie den Zwischenspeicher innerhalb der Funktionsdefinition halten (im Gegensatz zu einer globalen).
def fact(n):
if not hasattr(fact, 'mem'):
fact.mem = {1: 1}
if not n in fact.mem:
fact.mem[n] = n * fact(n - 1)
return fact.mem[n]
- See previous answers
- Weitere Antworten anzeigen
289 Stimmen
Wenn der zweite Satz des entsprechenden Wikipedia-Artikels den Satz "Mutually-recursive descent parsing[1] in einem allgemeinen Top-Down-Parsing-Algorithmus[2][3], der Mehrdeutigkeit und linke Rekursion in polynomialer Zeit und polynomialem Raum berücksichtigt" enthält, ist es meiner Meinung nach durchaus angebracht, SO zu fragen, was hier los ist.
14 Stimmen
@Clueless: Vor diesem Satz steht: "Die Memoisierung wurde auch in anderen Zusammenhängen (und zu anderen Zwecken als zur Geschwindigkeitssteigerung) verwendet, z. B. in". Es ist also nur eine Liste von Beispielen (und muss nicht verstanden werden); es ist nicht Teil der Erklärung der Memoisierung.
0 Stimmen
Hier ist eine gute Erklärung mit angehängten Beispielen der Memoisierung und wie man sie in einen Dekorator einbaut: pycogsci.info/?p=221
1 Stimmen
@StefanGruenwald Der Link ist tot. Können Sie bitte ein Update finden?
3 Stimmen
Neuer Link zur pdf-Datei, da pycogsci.info nicht erreichbar ist: people.ucsc.edu/~abrsvn/NLTK_parsing_demos.pdf
0 Stimmen
Sie können sich meinen Blogbeitrag unter u8y7541.github.io/blog_posts/lambdas_recursion_memoizing.html ansehen.
8 Stimmen
@Clueless, Der Artikel sagt eigentlich " einfach wechselseitig rekursives Descent-Parsing[1] in einem allgemeinen Top-Down-Parsing-Algorithmus[2][3], der Mehrdeutigkeit und linke Rekursion in polynomieller Zeit und polynomialem Raum berücksichtigt". Sie haben das einfach was dieses Beispiel natürlich viel klarer macht :).
1 Stimmen
Wenn ich sehe, wie viele Leute diese Frage beantwortet haben und immer noch beantworten, glaube ich an den "BIKE SHED EFFECT". de.wikipedia.org/wiki/Gesetz_der_Trivialität
1 Stimmen
@A_P zu dem Zeitpunkt, als Sie das geschrieben haben, waren alle 13 Antworten bis auf eine 5 Jahre alt (2014) und die letzte 3 Jahre alt (2016). Ich bin mir nicht sicher, ob das als "immer noch Antworten" zählt. Die Antwort, die ich gerade gepostet habe, fügt Überlegungen zur Geschwindigkeit hinzu, die ich in anderen Antworten noch nicht gesehen habe, und führt keine neue Methode oder ähnliches ein. Es gibt sicherlich Beispiele für das von Ihnen beschriebene Phänomen, aber ich bin mir nicht sicher, ob es das hier ist.