University of Free Knowledge
QA 76.73 · fol. 12

Private Names, Separate Parts

A function's local names are private to its own call, which lets you break a large problem into small, independently testable parts. · 11 min

A function does more than package steps — it seals off the names it makes. A variable created inside a function is local: it exists only inside that function, only while the call runs, and the code outside cannot see it. That privacy sounds like a limit, but it is the opposite. Because each function keeps its own names to itself, you can split one large problem into small functions that never trip over each other, and build them one at a time.

Guess before you learn

What happens when you run this program? `` def make(): secret = 42 make() print(secret) ``

THE DEPTH DIAL — the same idea, younger or deeper
9–12

9–12

Every function call gets its own private set of names — its local scope. A variable assigned inside a function is created when the call begins and destroyed when it ends; code outside cannot reach it. This is not a restriction to fight but a tool to use: because a function's names are sealed off, you can reason about it in isolation, sure it will not silently change or read anyone else's variables. Decomposition — splitting a task into small functions that each do one job and return a result — turns an overwhelming program into a list of parts you can build and check separately.

local scope

The set of names that exist only inside one function, only while its call runs. Code outside the function cannot see them.

Why is this true?

Why can two different functions each use a variable named count without interfering?

Because each function's names live in its own local scope, created fresh when the call starts and gone when it ends. One function's count and another's are separate names in separate scopes, so assigning one never touches the other.

call: double()x = 5private to doublecall: triple()x = 9private to triple
PLATE I Each call keeps its own x in its own scope. The two never collide.

Trace the scopes: does the inner x change the outer x? — the steps fade as you master them

1
Outside, x = 10. The call make_x() starts and assigns its own local x = 3. What is the function's local x?
inside make_x: x = 3
2
The line return x inside make_x hands back its local x. What does y hold?
y = make_x()
3
Does assigning x = 3 inside make_x change the outer x?
outer x is untouched
4
The call has ended, so its local x is gone. What does print(x) show for the outer x?
print(x)
Retrieval Gate — answer before you continue 0 / 4

1.What does this do? `` def f(): a = 5 f() print(a) ``

2.What does this print? `` def g(): n = 1 return n n = 99 g() print(n) ``

3.What does this print? `` def bump(v): v = v + 1 return v k = 5 bump(k) print(k) ``

4.In one sentence, explain what 'local scope' means for a variable created inside a function.

Private names are what make decomposition safe. To decompose a problem is to split it into small functions that each do one job and hand back a result. Because none of them can reach into another's local names, you can write one, test it until it is right, and move on — trusting it will keep working when the next part is added. A function's whole conversation with the rest of the program runs through its parameters coming in and its return value going out.

Ink That Thinks — guess first; the answer draws itself.
You are writing a program to print a shopping receipt total. Drag these jobs into a sensible order for small functions to run.

  1. read the list of item prices
  2. add the prices into a subtotal
  3. compute the tax on the subtotal
  4. add subtotal and tax into the grand total
Reorder, then commit.
PLATE II Decomposing one task into an ordered chain of functions — guess in graphite, truth in ink.
123main() ties it togethersubtotal(prices)add_tax(subtotal)grand_total(subtotal, tax)
PLATE III One hard problem split into small functions, each buildable and testable on its own.
Retrieval Gate — answer before you continue 0 / 4

1.Why break a long program into several small functions instead of one long block?

2.You are decomposing 'grade a quiz' into functions. Order the pieces into a sensible pipeline.

  1. read the answers in
  2. score each answer
  3. add up the score
  4. report the final grade

3.A well-decomposed function communicates with the rest of the program mainly through what?

4.What does this print? `` def inner(): return 2 def outer(): return inner() + 3 print(outer()) ``

That completes the functions unit. A function's names are private to its call, so you can decompose any large problem into small parts that each do one job and hand back a result, then test them one at a time. Next unit gives those functions something bigger to work on: lists and strings — collections that hold many values at once, and the everyday algorithms that scan them.

Practice — new ink and old, interleaved

1.What does this print? `` def mul(a, b): return a * b print(mul(6, 7)) ``

2.How many times does the body run? `` for i in range(4): print('hi') ``

3.What prints? `` def reset(): score = 0 return score score = 50 reset() print(score) ``

4.What prints? `` age = 20 if age >= 18: print('adult') else: print('minor') ``

5.How many lines does this program print? `` def pair(): print('a') print('b') pair() pair() ``

6.What is the difference between writing run and writing run()?

7.What does this print? `` def base(): return 10 def plus5(): return base() + 5 print(plus5()) ``

8.How many numbers does range(2, 12) produce?

9.How many times does the body run? `` i = 0 while i < 4: i = i + 1 ``

10.How many times does the body of this loop run? `` for i in range(2, 8): print(i) ``

The Call Slip — search everything Ctrl·K / ⌘K