Table of Contents
- The One Rule Behind the Series
- Method 1: A for loop, the classic
- Method 2: A while loop, up to a limit
- Method 3: Build a list you can reuse
- Method 4: Plain recursion, beautiful and slow
- Method 5: Recursion with memoization
- Method 6: A generator that streams the series
- Method 7: Binet's formula, no loop at all
- Which Method Should You Use?
- Mistakes to Watch For
- Frequently Asked Questions
- Seven Doors Into the Same Room
The Fibonacci series starts with 0 and 1, and every number after that is the sum of the two before it: 0, 1, 1, 2, 3, 5, 8, 13, 21. Simple enough to explain to a seven year old, and yet it has kept mathematicians busy for eight centuries and interviewers busy for decades.
For programmers, Fibonacci is something better than famous: it is the perfect practice problem. The same tiny task can be solved with a loop, a list, recursion, a cache, a generator, or a formula, and each solution teaches you a different corner of Python. That is exactly what this guide does, seven ways, every one run and verified before it was pasted here.
If loops themselves are still new, warm up with Python for beginners first. Otherwise, start counting.
The One Rule Behind the Series
Everything below rests on a single rule: the next term is the sum of the previous two. Watch the additions cascade and you already understand every method on this page.
Does it start with 0 or 1?
Both conventions exist. Modern maths and most programming courses start at 0, so this guide does too: 0, 1, 1, 2, 3, 5. If your textbook starts at 1, 1, 2, 3, just drop the leading zero. The rule does not change.
Method 1: A for loop, the classic
The version every teacher starts with. Two variables slide along the series, and the swap line does all the work.
n = 10
a, b = 0, 1
for i in range(n):
print(a, end=" ")
a, b = b, a + b
print()
0 1 1 2 3 5 8 13 21 34
Method 2: A while loop, up to a limit
Sometimes you do not want n terms, you want every term below a ceiling. A while loop fits that question naturally.
limit = 100
a, b = 0, 1
while a <= limit:
print(a, end=" ")
a, b = b, a + b
print()
0 1 1 2 3 5 8 13 21 34 55 89
Method 3: Build a list you can reuse
Printing is fine for homework, but real programs usually want the series as a list they can slice, sum, or search.
def fibonacci_list(n):
series = [0, 1]
while len(series) < n:
series.append(series[-1] + series[-2])
return series[:n]
print(fibonacci_list(10))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Method 4: Plain recursion, beautiful and slow
The definition of the series, typed straight in: each term is the sum of the two before it. It reads like maths, and for small n it is fine. But every call spawns two more calls, so the work explodes as n grows. We measured it below.
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(10))
print([fib(i) for i in range(10)])
55
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Method 5: Recursion with memoization
Same elegant code, plus one line. lru_cache remembers every answer the function has already worked out, so nothing is computed twice. The beauty of recursion at the speed of a loop.
from functools import lru_cache
@lru_cache(maxsize=None)
def fib(n):
if n <= 1:
return n
return fib(n - 1) + fib(n - 2)
print(fib(50))
12586269025
How much does that one cache line matter? We timed both versions computing fib(30) on an ordinary laptop while writing this post. Plain recursion took about 121 milliseconds because it makes over 2.6 million calls. The memoized version answered in well under a millisecond, thousands of times faster, because it makes just 31 real calls and remembers each one.
Method 6: A generator that streams the series
yield turns the function into a tap you can open one term at a time. It never builds the whole series in memory, so it can run forever if you let it.
def fibonacci():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
fib_gen = fibonacci()
first_ten = [next(fib_gen) for _ in range(10)]
print(first_ten)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
Method 7: Binet's formula, no loop at all
There is a closed formula for the nth term, built on the golden ratio. One calculation, no loop, no recursion. The catch: floating point rounding makes it drift for large n, so treat it as a curiosity beyond about the 70th term.
import math
def fib(n):
phi = (1 + math.sqrt(5)) / 2
return round(phi ** n / math.sqrt(5))
print([fib(i) for i in range(10)])
print(fib(30))
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
832040
Which Method Should You Use?
- Homework and exams: the for loop. Short, clear, impossible to get lost in.
- You need the terms afterwards: build the list.
- Interviews: start with recursion to show the idea, then add memoization to show you know its cost. That pairing is often the whole point of the question.
- Streams and big programs: the generator. It costs almost no memory and stops exactly when you do.
- Party trick: Binet's formula, with the floating point caveat attached.
Mistakes to Watch For
- Updating the variables in two steps: a = b then b = a + b uses the new a, which corrupts the series. Use the one-line swap: a, b = b, a + b.
- Forgetting the base case in recursion: without if n <= 1: return n, the calls never stop and Python raises RecursionError.
- Calling plain recursion with a big n: fib(40) makes over 300 million calls. If it feels frozen, it is not a bug, it is arithmetic. Add the cache.
- Off-by-one on the count: decide whether fib(0) is the first term or fib(1) is, and stay consistent. Print your first five terms and check them by hand.
- Trusting Binet's formula too far: floating point rounding makes it drift for large n. Loops and caches stay exact because they only ever add integers.
Try this next
Print the ratio of neighbouring terms: 5/3, 8/5, 13/8, 21/13. Watch the numbers settle toward 1.618, the golden ratio. It is the quiet link between the loop you just wrote and Binet's formula at the end.
Frequently Asked Questions
A sequence that starts 0, 1 and where every later number is the sum of the previous two: 0, 1, 1, 2, 3, 5, 8, 13. In Python it is most simply produced by a loop that repeats a, b = b, a + b, printing a each time.
The for loop in method 1: set a, b = 0, 1, then loop n times printing a and updating with a, b = b, a + b. Five lines, no imports, and it works for any n.
Because each call spawns two more, and the same sub-problems are recomputed enormously often. fib(30) alone triggers over 2.6 million calls. Memoization fixes it by caching every answer, cutting those millions of calls down to 31.
Remembering the results of function calls so repeated calls with the same input return instantly. Python ships it as a decorator: put @lru_cache above the function and the caching is automatic.
When you want the series as a stream rather than a fixed batch: take terms until one crosses a limit, or feed them into other code one at a time. A generator holds only two numbers in memory no matter how far you go.
Yes, Binet's formula computes it directly from the golden ratio: round(phi ** n / sqrt(5)). It is exact for small n but floating point rounding makes it unreliable beyond roughly the 70th term, so loops or cached recursion are safer for real use.
Often, though not as universally as posters claim. Sunflower seed spirals and pinecone scales frequently count to Fibonacci numbers because of how plants pack new growth. It is a genuine pattern with genuine exceptions.
Seven Doors Into the Same Room
One tiny series just walked you through loops, lists, recursion, caching, generators, and a formula. That is why Fibonacci refuses to retire: it is a whole programming course wearing a small disguise. The recursion-plus-memoization pairing in particular is your first real step into dynamic programming, which is the heart of our data structures and algorithms course.
For more practice at this level, try the HCF and LCM guide or list comprehensions next. And when you want a teacher beside you for the whole journey, our live coding courses welcome learners aged 6 to 67.