Functions are the building blocks of almost every Python program. They’re where the real action takes place! You’ve already used several functions such as print, len, and round. These are built‑in functions that come with Python. You can also create your own user‑defined functions to perform specific tasks.
Functions allow code reuse: instead of repeating similar code each time a program needs an operation, you simply call the function. But sometimes you need to repeat some code many times in a row—this is where loops come in.
In this chapter you will learn:
In earlier chapters, you used functions such as print() and len() to display text and determine the length of a string. But what exactly is a function? In this section, we’ll examine len() to understand what a function is and how it executes.
One of the most important properties of a function in Python is that functions are values—they can be assigned to variables. Try inspecting the name len in the interactive window:
Python tells you that len is a variable whose value is a built‑in function. Just like integers have type int and strings have type str, functions have a type builtin_function_or_method:
Because functions are values, you can reassign them—though it’s usually a bad idea:
Now len holds a string value instead of a function. As you might expect, type(len) now shows:
Although you can reassign names like len, doing so will shadow the built‑in function and cause confusion. To restore it, use the del keyword:
del removes the name binding, not the underlying object. Since len is built‑in, it reverts to its original definition automatically.
You can’t execute a function merely by typing its name; you must call it using parentheses.
An argument is the input passed into a function. Some functions take none, others many. len() requires one argument. When a function finishes executing, it returns a value as output. The process can be summarized in three steps:
For example:
len("four") computes 4 and replaces the call; after execution, the line effectively becomes num_letters = 4.
Most functions return a value, but some also produce side effects—changes observable outside the function. You’ve already used one with a side effect: print().
The text display is a side effect of print(), while its return value is None, an object of type NoneType that signifies “no data.”
When you call print(), the visible text output is not the return value—it is the side effect.
Now that you know that functions are values like numbers and strings, and how they are called and executed, the next section shows how to define your own functions.
As your programs grow longer and more complex, you may find that the same sequences of code repeat themselves. While copy‑pasting may seem tempting, it introduces unnecessary maintenance headaches and confusion. The best way to avoid repetition and errors is to extract reusable logic into functions.
Every function has two main parts:
Let’s write a simple function that multiplies two numbers. We’ll call it multiply():
Here’s how it works:
Everything indented beneath the signature belongs to the function body. Indentation defines scope in Python. By convention, you indent four spaces:
The first line creates a new variable product that stores the result of the multiplication. The second line uses the return keyword to send that value back to the caller. Once the return statement executes, the function immediately stops running.
You can include as many lines as needed in a function body, as long as they are all properly indented to the same level. After return, any further indented code will never run.
Once you’ve defined multiply(), you can call it elsewhere in your code. Simply write the function’s name followed by parentheses containing the arguments:
This displays:
Functions must be defined before they are called. If you attempt to call a function before Python has read its definition, you’ll encounter a NameError.
Every function technically returns a value, even if you omit return. When a function has no return statement, it defaults to returning None.
Output:
You see the message because print() inside the function produces a side effect. But greet()’s return value is None.
Python provides the built‑in help() tool and docstrings to keep function documentation in code. A docstring is a triple‑quoted string immediately following the function signature. Here’s an improved version of multiply() with a docstring:
In the interactive window, you can display this documentation by typing:
Docstrings explain the function’s purpose and expected parameters. Most Python developers follow the conventions defined in PEP 257 for writing clear, concise docstrings.
Here’s a complete example saved as multiply.py:
Output:
Hello name!using an f‑string.
Once you’ve mastered basic function definitions, you’re ready for the next section — a fun coding challenge on converting temperatures!
Write a script called temperature.py that defines two functions:
Your script should:
This practice reinforces multiple concepts — function definition, user input, type conversion, and formatting numeric output with round().
One of the great things about computers is that they never complain about doing repetitive tasks. A loop is a block of code that runs repeatedly — either a fixed number of times or until a condition is met. Python provides two primary loop structures: while and for.
A while loop executes its body as long as its condition remains true. When the condition becomes false, the loop stops.
Output:
On each iteration, Python evaluates the expression count < 5. If the expression is true, the body executes. Once count reaches 5, the loop exits.
If the condition of a while loop never becomes false, you’ve created an infinite loop! Use a control variable like count carefully to ensure the loop can terminate.
A for loop is used to iterate over a sequence (such as a list, tuple, string, or range). Unlike while, it automatically updates the loop variable each time.
This loop runs three times — once for each element in the list. Inside the loop, the variable color refers to each item in turn.
You can loop over a sequence of numbers generated by range(). For example:
Output:
Remember that range(3) generates 0, 1, and 2 — up to but not including 3.
Sometimes you need to alter the natural flow of a loop — either to exit early or skip a single iteration. Python provides two statements for this: break and continue.
Output:
The loop terminates immediately once num equals 4.
The continue statement jumps to the next iteration without running the rest of the body:
Output:
Use break for stopping a loop entirely and continue for skipping just one round of iteration.
You can combine functions with loops to perform repeated operations efficiently. For example, compute squares of numbers with a function and a for loop:
Output:
In this challenge, you will write a short program named invest.py that models how an investment grows over time. An initial deposit (principal amount) is made, and each year the total increases by a fixed percentage called the annual rate of return.
For example, an initial deposit of 100 with an annual rate of return of 5 increases to 105 the first year and then 110.25 the second year. Your task is to print the balance at the end of each year.
Define a function named invest() that accepts three parameters:
The function should print the balance for each year, rounded to two decimal places.
Whenever you create variables, Python keeps track of where those names exist. That region of code where a name is recognized is called its scope. Understanding scope is crucial because it determines which variables are visible to different parts of your program.
Variables defined inside a function exist only within that function and are said to have local scope. Variables created outside any function exist globally and can be accessed by any part of the program.
Output:
The two variables named x do not interfere with each other because they exist in different scopes.
Python resolves names using the **LEGB rule**: Local → Enclosing → Global → Built‑in.
len() and sum().The variable x is in the global scope, y is in the enclosing scope of outer_func, and z is local to inner_func. Python searches for names from local up to built‑in as needed.
While you can read a global variable inside a function, you cannot modify it unless you declare it using the global keyword. For example:
Output:
The global keyword allows a function to modify a variable outside its own scope, but this practice is considered poor style and often leads to hard‑to‑trace bugs. Prefer returning values instead of relying on global mutations.
As your programs grow more complex, debugging becomes an essential skill. Functions and loops introduce their own types of potential errors that you need to learn to identify and fix.
Missing or faulty return statements: Functions that should return a value but return None instead.
Wrong parameter handling: Functions called with wrong arguments or types.
Unreachable code: Code after return that never executes.
Infinite loops: The most common and dangerous loop bug. Always ensure the loop condition can become false.
Off-by-one errors: Loops that run one iteration too many or too few.
Print tracing: Add print statements to see what your code is doing.
Interactive testing: Test function components in the interactive window.
In this chapter, you learned how to create functions to organize and reuse code, how to control repetition with while and for loops, and how Python determines variable visibility with the LEGB scope resolution rule.
def.invest() and returns the final amount instead of printing each year's balance.print().End of Chapter 6 — Functions and Loops