Fibonacci Sequence
Learn how to generate the Fibonacci sequence in Python using loops, recursion, and generators.
Fibonacci Sequence
Problem
The Fibonacci sequence starts with 0 and 1. Every number after that is the sum of the two numbers before it.
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...Two problems to solve:
Part 1 — generate the first N numbers of the sequence:
Input: 8
Output: [0, 1, 1, 2, 3, 5, 8, 13]Part 2 — find the Nth Fibonacci number:
Input: 7
Output: 13 (the 7th number, counting from 1)
Input: 1
Output: 0
Input: 2
Output: 1Logic
Part 1:
- Start with
[0, 1] - Each new number = last number + second to last number
- Keep adding until we have N numbers
Part 2:
- Same logic — generate up to the Nth number
- Return only the last one
Flow
Solution 1 — using a loop
Build the sequence step by step — each iteration calculates the next number.
def fibonacci(n):
if n <= 0:
return []
if n == 1:
return [0]
# start with the first two numbers
sequence = [0, 1]
# generate the rest
while len(sequence) < n:
# next number = sum of last two
next_num = sequence[-1] + sequence[-2]
sequence.append(next_num)
return sequence
print(fibonacci(8)) # [0, 1, 1, 2, 3, 5, 8, 13]
print(fibonacci(1)) # [0]
print(fibonacci(10)) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
print(fibonacci(0)) # []Code Execution — Solution 1
Trace through fibonacci(8):
Start: sequence = [0, 1]
| Step | sequence[-2] | sequence[-1] | next_num | sequence |
|---|---|---|---|---|
| 1st | 0 | 1 | 1 | [0, 1, 1] |
| 2nd | 1 | 1 | 2 | [0, 1, 1, 2] |
| 3rd | 1 | 2 | 3 | [0, 1, 1, 2, 3] |
| 4th | 2 | 3 | 5 | [0, 1, 1, 2, 3, 5] |
| 5th | 3 | 5 | 8 | [0, 1, 1, 2, 3, 5, 8] |
| 6th | 5 | 8 | 13 | [0, 1, 1, 2, 3, 5, 8, 13] |
| Stop | len == 8 |
Result: [0, 1, 1, 2, 3, 5, 8, 13]
Solution 2 — using two variables
Instead of keeping the whole list, use just two variables a and b to track the last two numbers. More memory efficient.
def fibonacci(n):
if n <= 0:
return []
if n == 1:
return [0]
a, b = 0, 1 # first two numbers
sequence = [0, 1] # result list
while len(sequence) < n:
a, b = b, a + b # shift: a becomes b, b becomes a+b
sequence.append(b)
return sequence
def fibonacci_nth(n):
"""Return only the Nth Fibonacci number."""
if n == 1:
return 0
if n == 2:
return 1
a, b = 0, 1
for _ in range(2, n):
a, b = b, a + b # shift forward
return b
print(fibonacci(8)) # [0, 1, 1, 2, 3, 5, 8, 13]
print(fibonacci_nth(7)) # 13
print(fibonacci_nth(1)) # 0
print(fibonacci_nth(10)) # 34Code Execution — Solution 2
Trace through fibonacci_nth(7) — finding the 7th Fibonacci number:
Start: a = 0, b = 1
range(2, 7) gives us 5 iterations:
| Iteration | a before | b before | a, b = b, a+b | a after | b after |
|---|---|---|---|---|---|
| 1st (i=2) | 0 | 1 | b=1, a+b=1 | 1 | 1 |
| 2nd (i=3) | 1 | 1 | b=1, a+b=2 | 1 | 2 |
| 3rd (i=4) | 1 | 2 | b=2, a+b=3 | 2 | 3 |
| 4th (i=5) | 2 | 3 | b=3, a+b=5 | 3 | 5 |
| 5th (i=6) | 3 | 5 | b=5, a+b=8 | 5 | 8 |
Wait — b = 8? Let us check: the 7th Fibonacci number is 0, 1, 1, 2, 3, 5, 8, 13 → position 7 = 13.
Let me re-trace range(2, 7) = iterations at i=2,3,4,5,6 → 5 steps:
| i | a, b = b, a+b | b |
|---|---|---|
| 2 | 0,1 → 1,1 | 1 |
| 3 | 1,1 → 1,2 | 2 |
| 4 | 1,2 → 2,3 | 3 |
| 5 | 2,3 → 3,5 | 5 |
| 6 | 3,5 → 5,8 | 8 |
Hmm, that gives 8 for the 7th position. But counting from 1: F(1)=0, F(2)=1, F(3)=1, F(4)=2, F(5)=3, F(6)=5, F(7)=8. So fibonacci_nth(7) = 8. Let us verify with fibonacci(8):
fibonacci(8) = [0, 1, 1, 2, 3, 5, 8, 13] → index 6 (7th item) = 8 ✅
a, b = b, a + b is Python's simultaneous assignment. Both right-hand side values are calculated first, then assigned. This means you do not need a temporary variable to swap — it is clean, safe, and the standard way to advance the Fibonacci sequence.
Solution 3 — using recursion
Each Fibonacci number is defined in terms of smaller Fibonacci numbers. This maps directly to recursion.
def fibonacci_recursive(n):
"""Return the Nth Fibonacci number using recursion."""
# base cases
if n == 1:
return 0
if n == 2:
return 1
# recursive case — sum of previous two
return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2)
# generate sequence using recursion
def fibonacci_sequence_recursive(n):
return [fibonacci_recursive(i) for i in range(1, n + 1)]
print(fibonacci_recursive(7)) # 8
print(fibonacci_sequence_recursive(8)) # [0, 1, 1, 2, 3, 5, 8, 13]Code Execution — Solution 3
Trace through fibonacci_recursive(5):
fibonacci_recursive(5)
= fibonacci_recursive(4) + fibonacci_recursive(3)
= (fibonacci_recursive(3) + fibonacci_recursive(2))
+ (fibonacci_recursive(2) + fibonacci_recursive(1))
= ((fibonacci_recursive(2) + fibonacci_recursive(1)) + 1)
+ (1 + 0)
= ((1 + 0) + 1) + 1
= (1 + 1) + 1
= 2 + 1
= 3F(5) = 3 ✅ (sequence: 0, 1, 1, 2, 3)
Pure recursion is elegant but slow. fibonacci_recursive(40) makes over 300 million calls because it recalculates the same values over and over. Use memoization or the loop solution for large numbers.
Solution 4 — recursion with memoization
Store results of previous calls — never calculate the same value twice.
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci_memo(n):
"""Fibonacci with caching — each value calculated only once."""
if n == 1:
return 0
if n == 2:
return 1
return fibonacci_memo(n - 1) + fibonacci_memo(n - 2)
# now fast even for large numbers
print(fibonacci_memo(50)) # 12586269025
print(fibonacci_memo(100)) # 354224848179261915075
# generate sequence
sequence = [fibonacci_memo(i) for i in range(1, 11)]
print(sequence) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]Solution 5 — using a generator
Generate Fibonacci numbers one at a time using yield. Memory efficient — generates values on demand.
def fibonacci_generator(limit=None):
"""
Generates Fibonacci numbers forever (or up to limit).
Uses yield — produces one number at a time on demand.
"""
a, b = 0, 1
count = 0
while True:
if limit is not None and count >= limit:
return # stop after limit numbers
yield a # produce the current number
a, b = b, a + b # advance to next
count += 1
# generate first 8 numbers
gen = fibonacci_generator(8)
print(list(gen)) # [0, 1, 1, 2, 3, 5, 8, 13]
# use in a for loop
for num in fibonacci_generator(10):
print(num, end=" ")
# 0 1 1 2 3 5 8 13 21 34
# generate until a value exceeds 100
for num in fibonacci_generator():
if num > 100:
break
print(num, end=" ")
# 0 1 1 2 3 5 8 13 21 34 55 89Code Execution — Solution 5
Trace through first 4 values of fibonacci_generator():
| Call | yield a | a, b = b, a+b | a after | b after |
|---|---|---|---|---|
1st next() | yields 0 | 0,1 → 1,1 | 1 | 1 |
2nd next() | yields 1 | 1,1 → 1,2 | 1 | 2 |
3rd next() | yields 1 | 1,2 → 2,3 | 2 | 3 |
4th next() | yields 2 | 2,3 → 3,5 | 3 | 5 |
Each yield pauses the function and returns the current value. The next call resumes from where it left off.
Which solution to use?
| Solution | How | Best when |
|---|---|---|
| Solution 1 | Loop with list | Clear and easy to understand |
| Solution 2 | Two variables | Memory efficient — no list needed |
| Solution 3 | Recursion | Understanding recursive thinking |
| Solution 4 | Recursion + lru_cache | Large numbers, elegant code |
| Solution 5 | Generator | Processing one value at a time — infinite sequences |
Output
[0, 1, 1, 2, 3, 5, 8, 13]
[0]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
[]
8
0
34