«Базовый» смысл без использования lru_cache.Все это «достаточно быстро» - я не ищу самый быстрый алгоритм - но время меня удивило, поэтому я надеялся, что смогу кое-что узнать о том, как «работает» Python.
Простой цикл (/ хвостовая рекурсия):
def fibonacci(n):
a, b = 0, 1
if n in (a, b): return n
for _ in range(n - 1):
a, b = b, a + b
return b
Простое запоминание:
def fibonacci(n, memo={0:0, 1:1}):
if len(memo) <= n:
memo[n] = fibonacci(n - 1) + fibonacci(n - 2)
return memo[n]
Использование генератора:
def fib_seq():
a, b = 0, 1
yield a
yield b
while True:
a, b = b, a + b
yield b
def fibonacci(n):
return next(x for (i, x) in enumerate(fib_seq()) if i == n)
Я ожидал, что первое, простое до смерти, будетсамый быстрый.Это не.Второй, безусловно, самый быстрый, несмотря на рекурсию и множество вызовов функций.Третий классный и использует «современные» функции, но еще медленнее, что разочаровывает.(У меня было искушение думать о генераторах как о некоторой альтернативе запоминанию - так как они помнят свое состояние - и поскольку они реализованы в CI, надеялись, что они будут быстрее.)
Типичные результаты:
loop: about 140 μs
memo: about 430 ns
genr: about 250 μs
Так может кто-нибудь объяснить, в частности, почему запоминание на порядок быстрее простого цикла?
РЕДАКТИРОВАТЬ:
Теперь ясно, что я (как и многие другие до меня) просто наткнулся на изменяемые аргументы Python по умолчанию .Такое поведение объясняет реальное и видимое увеличение скорости выполнения.