Ist frozenset ausreichend für das Caching von symmetrischen Eingangsdaten in einem Python dict?

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

  •  24-09-2019
  •  | 
  •  

Frage

Der Titel mehr oder weniger schon sagt:

I haben eine Funktion, die in zwei Argumente symmetrische Eingabe nimmt, z.B. so etwas wie

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

Jetzt möchte ich einige Caching-Verfahren einzuführen. Wäre es richtig / pythonic / ziemlich effizient sein, so etwas zu tun:

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

Oder wäre es eine bessere Art und Weise sein?

Bearbeiten : a1 und a2 können die Zeilen einer numpy Array sein; warum das ich sie in einem Tupel wickeln jeden.

War es hilfreich?

Lösung

Python berechnet immer alle Argumente Sie an eine Funktion, und erst dann wird es die Funktion aufrufen. Mit anderen Worten, wie die meisten anderen Sprachen, ist Python „eifrig“ in seiner Bewertung (die große Ausnahme ist heute wahrscheinlich Haskell, aber das macht man nicht helfen, -).

So setdefault ist ein sehr ungeeigneter Ansatz für das Caching! Wann immer Sie tun

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

Sie sind ersten Aufruf f(x, y) mit all seinen Rechenkosten, und vielleicht auf dem Boden, die Ergebnisse dieser Berechnung fallen; dies macht das Caching völlig wirkungslos.

Vielmehr immer es wie folgt tun:

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

oder dergleichen - es gibt ein paar anderen möglichen Idiome, vor allem, wenn z.B. Sie wissen, dass f nie None zurück:

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

Wie für die sekundäre Frage, was ist eine angemessene whatever für die Schlüsselberechnung gegeben, dass Sie wissen, dass f symmetrisch ist, glaube ich, frozenset wahrscheinlich in Ordnung ist; obwohl (wenn die Komponenten von x und y vergleichbar sind, sowie hashable - das heißt, es würde nicht funktionieren mit komplexen Zahlen) Sie könnten in Erwägung ziehen

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

die relative Leistung hängt von den Kosten zu vergleichen, gegen die der Hashing, die Elemente in a1 und a2. Die Unterschiede sind wahrscheinlich gering, trotzdem sein.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top