Key Takeaways: Functions — Writing Reusable Code

One-Sentence Summary

Functions let you name a chunk of behavior, define its inputs and outputs, and reuse it without thinking about its internals — this is abstraction, the single most important concept in computer science.

Function Anatomy

def function_name(param1, param2="default"):   # Definition
    """One-line description of what this function does."""
    # body — the code that runs when called
    return result                                # Output

value = function_name(arg1, arg2)               # Call

Key Distinctions

Concept Meaning
Parameter Variable name in the function definition (a placeholder)
Argument Actual value passed when calling the function
def Defines the function (doesn't execute it)
Calling Executes the function (uses parentheses)
Local variable Exists only inside the function that creates it
Global variable Created at the module level; any function in the file can read it

Return vs. Print

return print()
Sends data to The calling code The screen
Can be stored in a variable Yes No (returns None)
Can be used in calculations Yes No
Use when Computing a result Displaying output to the user

Parameter Types

Type Example When to Use
Positional greet("Alice") Simple functions with few parameters
Keyword greet(name="Alice") Clarity when calling functions with many parameters (in a call, keyword arguments go after positional ones)
Default def greet(name, greeting="Hello"): Providing sensible fallbacks
*args def average(*scores): Accepting any number of arguments, passed as separate values (average(85, 90), not average([85, 90]))

Scope (LEGB Rule)

Python looks up variables in this order: 1. Local — inside the current function 2. Enclosing — inside enclosing functions (nested functions) 3. Global — at the module level 4. Built-in — Python's built-in names (print, len, etc.)

Critical rule: Assigning to a variable inside a function makes it local. If you need to read a global, that works. If you need to modify a global, pass it as a parameter and return the new value — don't use global.

Rebinding vs. mutating: n = n * 2 inside a function never changes the caller's variable. But a list passed in can be changed in place (tasks.append(...)), and the caller sees that change, because both names point to the same list.

The Call Stack

  • Every function call pushes a stack frame (its parameters, local variables, and where to return to); every return pops it off.
  • Python always runs the frame on top of the stack. Local variables vanish when their frame is popped.
  • A traceback is a snapshot of the stack at the moment of a crash: oldest call first, most recent call last, error message at the bottom. Start reading at the bottom.

Function Design Checklist

  • [ ] Does the function have a clear, descriptive name (verb + noun)?
  • [ ] Does it do exactly one thing (single responsibility)?
  • [ ] Does it return its result rather than printing it (when computing)?
  • [ ] Does it have a docstring explaining what it does?
  • [ ] Are its parameter names descriptive?
  • [ ] Does it avoid mutable default arguments?
  • [ ] Can it be tested independently?

The Three Most Common Bugs

  1. Forgetting return — function prints instead of returning, caller gets None
  2. Mutable default argument — def f(items=[]) shares the list across calls; use None instead
  3. Scope confusion — assigning to a name inside a function creates a local, potentially shadowing a global

Threshold Concept: Abstraction Through Functions

  • Before: "I write one big block of code that does everything."
  • After: "I build programs from small, reusable, well-named pieces."

This shift in thinking is the most important takeaway from this chapter. Abstraction through functions is the foundation that everything in the rest of this course builds on — data structures, modules, classes, APIs, and testing all rely on the idea that you can hide complexity behind a meaningful name.

What's Next

Chapter 7: Strings — text processing with indexing, slicing, and string methods. TaskFlow v0.6 adds keyword search, using the function-based architecture you built in this chapter.