Является ли FORZENSET адекватным для кэширования симметричных входных данных в Python Dict?

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

  •  24-09-2019
  •  | 
  •  

Вопрос

Название более или менее говорит все это:

У меня есть функция, которая принимает симметричный вход в два аргумента, например, что-то вроде

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

Теперь я хочу внести метод кэширования. Было ли это правильно / питон / разумно эффективно делать что-то вроде этого:

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

Или будет ли какой-то лучший способ?

Редактировать: a1 и a2 могут быть рядами Numpy Array; Вот почему я обернутую их в кортеже каждый.

Это было полезно?

Решение

Python всегда вычисляет все аргументы, которые вы передаете на функцию, и только тогда он вызывает функцию. Другими словами, как и большинство других языков, Python «нетерпелив» в его оценке (главное исключение сегодня, вероятно, Haskell, но это не поможет вам ;-).

Так setdefault это очень Не подходящий подход к кэшированию! Всякий раз, когда вы делаете

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

Вы первый призыв f(x, y), со всеми его вычислительными ценами, тогда возможно, бросая результаты этого вычисления на полу; Это делает кэширование совершенно неэффективным.

Скорее, всегда делай это следующим образом:

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

или тому подобное - есть несколько других возможных идиом, особенно если вы знаете, что f никогда не вернутся None:

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

Что касается вторичного вопроса того, что является подходящим whatever для ключевых вычислений, учитывая, что вы знаете, что f симметрично, я думаю frozenset вероятно, хорошо; Хотя (если компоненты x а также y сопоставимы, как и hashable - то есть это не будет работать со сложными числами), вы можете рассмотреть

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

Относительная производительность зависит от стоимости сравнения, против качества перемешивания, предметов в a1 а также a2. Отказ Различия, вероятно, будут незначительными, в любом случае.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top