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
сопоставимы, а также хешируемы - то есть не будут работать с комплексными числами), вы можете рассмотреть
ta1 = tuple(a1)
ta2 = tuple(a2)
if ta1 > ta2: key = ta1, ta2
else: key = ta2, ta1
Относительная производительность зависит от стоимости сравнения, по сравнению с хэшированием, пунктов в a1
и a2
. Различия, скорее всего, будут незначительными.