Python Function Calls and the Stack—Lesson 2

code/theStack01.py
1def foo():
2 print("foo line 1")
3 print("foo line 2")
4 print("foo line 3")
5
6def fum():
7 print("fum line 1")
8 print("fum line 2")
9 print("fum line 3")
10
11def bar():
12 print("bar line 1")
13 fum()
14 foo()
15 print("bar line 4")
16
17def go():
18 bar()
19
20go()
—end of file—

Press the ⍄ key above to move forward through the program, and the ⍃ key to move back.

__main__
done
—bottom of stack—

Let's review an important idea from Lesson 1:

In Lesson 2 we ask the question: How does this work?

Answer: the run time stack—or just the stack for short.

The run time stack includes two kinds of things:

  1. call frames—one for each function call
  2. storage for local variables.

In this lesson, we focus on the call frames
(local variables are covered in lesson 3).

A call frame is just an area of memory that is set aside to keep track of a function call in progress. Call frames are born when a function is called, and they die when a function returns.

Call frames (a.k.a. activation records)
are kept on the run time stack:

Each call frame contains the name of the function that was called, and "where to pick up from" (as a line number) when the function call returns.

The code from lesson 1 is repeated at the right hand side of this web page—beside it is a representation of the stack.

Initially, the stack has a call frame called __main__. As functions are called, more call frames are put on the stack. Each call frame contains the name of the function that was called, and "where to pick up from" when the function call returns. The call frame on top of the stack is always the currently running function. When that function returns, it's call frame is popped off the stack.

Observe what happens when you click the arrows to step forward and backwards through the code:

When popping a frame, the symbol moves to the
"place to pick up from" from the removed top frame.

A detail not shown in this animation is that print() is also a function—so each time print() is executed, it actually has its own call frame placed on the stack—the value is printed—and then the call frame is immediately removed. To simplify things, I've left that part out—but it is important to keep in mind.

In lesson 3, we'll look at how local variables are stored on the stack.