You think calling a function is cheap. It isn’t.

Every function call has a cost.

Today, you understand what actually happens when Python executes functions.


Today’s Goal

By the end of today, you will:

  • Understand how function calls work internally
  • Learn what a call stack is
  • Visualize execution flow
  • Understand performance impact of function calls

The Illusion

def add(a, b):
    return a + b

add(2, 3)

You think:

Python just jumps into the function

Reality:

Python creates a new execution frame and pushes it to the stack


What Is a Call Stack?

Top → [Frame: add]
       [Frame: main]
Bottom

A stack of execution frames.


What Happens During Function Call

When you call a function:

  1. Create a new frame
  2. Store local variables
  3. Push frame to stack
  4. Execute function
  5. Pop frame when done

Example

def f1():
    f2()

def f2():
    f3()

def f3():
    print("done")

f1()

Stack Visualization

[ f3 ]
[ f2 ]
[ f1 ]
[ main ]

Then unwinds after execution.


Key Insight

Function calls are NOT free.

Each call involves:

  • frame creation
  • memory allocation
  • stack operations

Recursion and Stack Growth

def recurse(n):
    if n == 0:
        return
    recurse(n-1)

Each recursive call adds a frame.


Stack Overflow Risk

Too many calls:

RecursionError: maximum recursion depth exceeded

Python Recursion Limit

import sys
print(sys.getrecursionlimit())

Default ~1000


Why Limit Exists

To prevent:

  • memory exhaustion
  • crash due to deep recursion

Function Call Overhead

Compare:

# direct
x = 10 + 5

# function
add(10, 5)

Function call is slower due to overhead.


Performance Insight

In tight loops:

  • avoid unnecessary function calls
  • inline simple logic if needed

Local vs Global Lookup

x = 10

def f():
    return x

Python searches:

  1. local scope
  2. global scope
  3. builtins

Cost of Lookup

Local lookup is fastest. Global is slower.


Optimization Trick

def f(x=x):
    return x

Caches global into local scope.


Why This Matters

Function behavior impacts:

  • performance
  • memory usage
  • recursion safety

Real Example

def square(x):
    return x * x

for i in range(1_000_000):
    square(i)

Repeated function calls add overhead.


Your Task

  • trace a function call manually
  • draw the call stack
  • compare recursion vs loop performance

Common Mistakes

  • overusing recursion
  • ignoring call overhead
  • deep nesting of function calls

Think Deeper

  1. What happens in memory during function call?
  2. Why are recursive calls risky?
  3. When should you avoid function calls?

Subtle Insight (CRITICAL)

Python execution is stack-driven.

Understanding the stack = understanding execution.


Tomorrow

Modules & Imports — how Python loads and links code


Rule

  • Functions improve structure, not always performance
  • Be aware of call cost

See you in Day 6.