Вы можете сами произвести замеры, но ставлю на то, что быстрее окажется проверка по словарю, поскольку она делается за ~O(1) благодаря хешированию.
Однако я бы предложил чуть более эффективню схему:
D = dict()
NOTFOUND = object()
def f1(x):
result = D.get(x, NOTFOUND)
if result is NOTFOUND:
result = D[x] = long_calculation()
return result
Не поленитесь (как я), сделайте замеры. Всем тут будет интересно.
А ещё в питоне как-то не принято экономить на спичках в ущерб чтаемости и прозрачности кода.
Но если всё как следует "посахарить"... Лучше всего такое кэширование смотрится в виде декоратора.
UPD:
Забавно. Я ошибся и с исключением действительно выходит быстрее. На это указал уже автор вопроса, а я на всякий случай пересчитал, причем по отдельности для прогрева, для повторного взятия и для неполучения из прогретого хеша.
import time
from math import tan, atan
import timeit
NOTFOUND = object()
def long_calculation(x):
return atan(tan(x) / 2)
def f1(x):
if x not in D:
D[x] = long_calculation(x)
return D[x]
def f2(x):
try:
return D[x]
except:
D[x] = long_calculation(x)
return D[x]
def f3(x):
result = D.get(x, NOTFOUND)
if result is NOTFOUND:
result = D[x] = long_calculation(x)
return result
FUNCS = (
(f1, 'get triple'),
(f2, 'except'),
(f3, 'get once'),
)
def work(f, gap=0.1, count=1000):
for x in range(0, count):
f(x + gap)
D = {}
number = 10000
for func, descr in FUNCS:
print(f'{func.__name__} ({descr}):')
print(f' Cache empty:', timeit.timeit(f"work({func.__name__})", setup=f'D=dict()', globals=globals(), number=number))
print(f' Total reuse:', timeit.timeit(f"work({func.__name__})", setup=f'D=dict(); work({func.__name__})', globals=globals(), number=number))
print(f' Total miss :', timeit.timeit(f"work({func.__name__})", setup=f'D=dict(); work({func.__name__}, gap=0.2)', globals=globals(), number=number))
И вот результат:
f1 (get triple):
Cache empty: 2.8940897800493985
Total reuse: 1.7486431139986962
Total miss : 1.6964515489526093
f2 (except):
Cache empty: 1.2670072519686073
Total reuse: 1.2622331579914317
Total miss : 1.2547212480567396
f3 (get once):
Cache empty: 1.6983374420087785
Total reuse: 1.6465996010228992
Total miss : 1.6999219709541649