Functions

The structuring unit without which programming gets very uncomfortable very quickly.

Fundamentals 12 min Beginner April 26, 2026

Every Python command you have used so far — print(), input(), range(), len() — is a function someone else wrote. Functions are the fundamental building block of every program: they take input, do work, and return a result.

In this article, you will learn to build your own functions, understand why they make code shorter and safer, and discover scope — the invisible rules that prevent variables inside functions from leaking out and causing chaos.

What Is a Function?

You have been calling functions since your first line of Python. Here are eight you already know:

print() Outputs text to the screen
input() Reads keyboard input as a string
range() Generates a sequence of numbers
len() Counts elements in a collection
type() Shows the data type of a value
int() Converts to a whole number
str() Converts to a string
float() Converts to a decimal number

Function

AnalogyDefinition
A function is like an electric juicer. You put in oranges (input/parameters), press the button (function call), the machine does internal work you don't need to understand (processing), and out comes orange juice (return value). You only need to know what goes in and what comes out.

The juicer analogy works well for input/output and abstraction. But a juicer can only juice — a function can contain any logic including conditionals, loops, and calls to other functions. Some functions take no input, and some return no meaningful result.

How a Function Call Works

1
Python sees the call greet("Ada")
2
The argument "Ada" is bound to the parameter name
3
The function body executes: f"Hello, {name}!"
4
return sends the value "Hello, Ada!" back
5
The caller receives the string and can use it further
print()

Displays text on the screen but returns None. The result cannot be stored in a variable or used further. Good for displaying, not for computing.

return

Sends a value back to the caller. The result can be stored in a variable, processed further, or passed to another function. This is how you get data out of a function.

Common Mistake: print() Instead of return

Beginners often confuse print() and return. A function that only uses print() does display something — but the caller receives None instead of a usable value.

def double(x):
    print(x * 2)    # Shows 10...

result = double(5)
print(result)         # ...but result is None!

The correct version: return x * 2 — then result holds the value 10 and can be used further.

Why Functions? DRY and Modularization

DRY Principle

AnalogyDefinition
Imagine giving directions to five different restaurants. Without functions, you repeat the full route from the train station to the city center each time, then add the restaurant-specific part. With functions, you define route_to_center() once and reuse it: "Take the usual route to the center, then turn right twice." The function name acts as a readable shorthand.

The directions analogy works well: repeated sub-routes are factored out, the name serves as a reference, and one change propagates everywhere. In real life, you can rely on implicit knowledge ("you know the way") — in code, every instruction must be explicit.

Example: Gross Price Calculation

Without a function — the same formula copied three times:

price1 = 100 * 1.19    # 119.0
price2 = 250 * 1.19    # 297.5
price3 = 49.90 * 1.19  # 59.381

With a function — the formula exists only once:

def gross(net):
    return net * 1.19

price1 = gross(100)    # 119.0
price2 = gross(250)    # 297.5
price3 = gross(49.90)  # 59.381

If the tax rate changes from 19% to 16%, you update one single line instead of searching through the entire program.

Modularization means splitting a big problem into small, named functions. Each function has one clear job: load_data(), validate(), process(), display(). The function names act like an outline — you can read the program flow without understanding every single step.

Misconception: Functions Are Only for Large Programs

Even a 20-line script benefits from structure. If you write the same logic twice, that is a sign: extract it into a function. And copy-paste with small tweaks is not a solution — parameterize the differences instead.

Scope — Where Variables Live and Die

Scope (Variable Visibility)

AnalogyDefinition
Think of a hotel. The lobby is the global scope — everyone can see and use it. Your room is the local scope of a function. Things you leave in your room (local variables) are only available there. When you check out (function ends), the room is cleaned and its contents disappear.

The hotel analogy works well: public space (global) vs. private space (local), and contents disappear after checkout. But in a hotel, you can carry objects from your room to the lobby — in Python, you must return values and assign them outside.

Example: Same Name, Different Scope

message = "I am global"

def show_message():
    message = "I am local"
    print(message)      # "I am local"

show_message()
print(message)          # "I am global"

Inside the function, a separate variable message exists that shadows the global one. The global variable remains unchanged — this is exactly the intended behavior. Scope keeps functions independent from each other.

Error: Accessing Outside the Scope

def calculate():
    x = 42

calculate()
print(x)    # NameError: name 'x' is not defined

The variable x exists only inside the function calculate(). After the call, it is gone — like a hotel room after checkout.

Warning: Modifying Global Variables in Functions

The global keyword allows a function to directly modify global variables. This works — but it is almost always a bad idea because it makes functions dependent on their environment and bugs become hard to track down.

counter = 0

def increment():
    global counter
    counter += 1

increment()
print(counter)    # 1

Prefer return over global. The clean approach: return the new value and assign it outside.

Interactive: Function Call Step by Step

You learned that local variables exist only inside their function. But WHERE exactly do they live? Click through the steps of a function call and observe the call stack — the internal data structure where Python creates a separate frame for each call. Watch how variables appear in the frame and disappear when the function returns.

1
2
3
4
5
6
Code
1def greet(name):
2 msg = f"Hello, {name}!"
3 return msg
4
5result = greet("Ada")
6print(result)
Call Stack
<module>
(empty)
Step 1 / 6Start

Python encounters the line result = greet("Ada"). It recognizes a function call and prepares to execute the function greet.

Parameters can have default values. If no argument is passed during the call, the default is used:

def greet(name="World"):
    return f"Hello, {name}!"

print(greet())         # "Hello, World!"
print(greet("Ada"))    # "Hello, Ada!"

With keyword arguments you can address parameters by name: greet(name="Ada"). With multiple parameters, this makes the code more readable because the order no longer matters.

Caution: never use an empty list as a default value (def f(items=[])). Python creates the default only once — the list accumulates entries across multiple calls. Use items=None instead and create the list inside the function body.

The true power of functions shows when one function's return value becomes the input for the next — a pipeline of small, specialized building blocks:

def load(file):
    return open(file).read()

def clean(text):
    return text.strip().lower()

def count(text):
    return len(text.split())

# Pipeline: load -> clean -> count
content = load("data.txt")
cleaned = clean(content)
word_count = count(cleaned)
print(f"{word_count} words")

In later articles, you will see this pattern in data processing and machine learning workflows.

Key Takeaways

  1. A function is defined with def, takes parameters as input, and uses return to send a result back. Without return, the function returns None.
  2. print() displays text on the screen but returns None. return passes a value back to the caller for further use. They are not interchangeable.
  3. The DRY principle: write logic once, call it everywhere. When the logic changes, you fix it in one place.
  4. Modularization means splitting a big problem into small, named functions. Each function has one clear job.
  5. Variables inside a function are local — they exist only while the function runs and are invisible outside. This isolation makes functions reusable without side effects.

Quiz: Functions

Question 1 / 4
Not completed

What does a function return if it has no return statement?

Select one answer
Answer Key: 1) C · 2) B · 3) B · 4) B

Checkpoint

  • What is the difference between defining a function with def and calling it with parentheses? When does the code inside the function body actually execute?
  • Why is it better to put a recurring calculation like a VAT computation into its own function instead of copying the same code block multiple times?
  • Why does print(x) outside a function cause a NameError if x was only defined inside the function? Explain using the concept of scope.