This session finishes off loops (patterns, nested loops, loop control) and then dives properly into strings.

Population program

Current population is 10000 and it grows 10% every year. We want the population at the end of each of the last 10 years, so we walk backwards. Going back one year undoes a 10% increase, which means dividing by 1.1.

curr_pop = 10000

for i in range(10, 0, -1):      # counts 10, 9, 8, ... down to 1
    print(i, curr_pop)
    curr_pop = curr_pop / 1.1   # step one year into the past

Output (decimals get long, shown rounded):

10 10000
9  9090.91
8  8264.46
7  7513.15
6  6830.13
5  6209.21
4  5644.74
3  5131.58
2  4665.07
1  4240.98

We print first, then divide. So year 10 shows the full 10000, and each earlier year is a bit smaller.

Sequence sum

Add up 1/1! + 2/2! + 3/3! + ... for n terms. Instead of recomputing the factorial every time, we grow it step by step.

n = int(input('enter n'))

result = 0
fact = 1

for i in range(1, n+1):
    fact = fact * i          # fact becomes i! one step at a time
    result = result + i/fact

print(result)

If you enter 5:

2.708333333333333

Tiny bit of trivia: each term i/i! is the same as 1/(i-1)!, so this sum slowly creeps towards the number e (about 2.718) as n grows.

Nested loops

A loop inside a loop. For every single value of the outer loop, the inner loop runs all the way through.

for i in range(1, 5):
    for j in range(1, 5):
        print(i, j)

Output (every pair, 4 x 4 = 16 lines):

1 1
1 2
1 3
1 4
2 1
2 2
...
4 4

Patterns

Patterns are the classic use of nested loops. Outer loop → rows, inner loop → what to print on each row.