# Defining and Calling Functions

> Chapter 13 of the Courseiva PYTHON-PCEP curriculum — https://courseiva.com/learn/python-pcep/defining-and-calling-functions

**Official objective:** 5.1 — Define custom functions using def, parameters, and return values.

## Introduction

How do you avoid repeating the same code over and over when writing a Python program? Functions let you package a set of instructions into a reusable block that you can run (call) any time you need it. For the PCEP-30-02 exam, understanding how to define your own functions using 'def', pass data into them with parameters, and send results back with 'return' is essential — it's a fundamental building block of writing clean, efficient code.

## The Recipe Book Analogy

Have you ever tried to cook a meal without a recipe, only to find yourself overwhelmed by chopping, timing, and forgetting key steps?

A function in Python is exactly like a recipe in a cookbook. A recipe gives a series of clear, named instructions (like "bake at 180°C for 25 minutes") that you can reuse whenever you want that dish. You don't have to explain the entire cooking process each time — you just say "make the chocolate cake" and your kitchen team follows the pre-written steps.

In programming, a function is a named block of code that performs a specific task. When you 'call' a function, you're telling the computer "run those instructions now." Just like a recipe might ask for ingredients (milk, eggs, flour), a function can take inputs called 'parameters' and can produce a result called a 'return value' — the finished dish.

For example, a recipe for 'calculate_total' might take 'price' and 'sales_tax' as ingredients and return the final bill. You can use this recipe a hundred times with different prices, and you never need to rewrite the calculation steps. This saves time, reduces mistakes, and makes your code much easier to read — just like a well-organised cookbook.

## Core explanation

A function is a named, reusable block of code that performs a specific task. Think of it as your own custom command that you teach Python. Instead of writing the same five lines of code every time you need to greet a user, you write a function called 'greet_user' once, and then call it whenever needed.

To create a function, you use the 'def' keyword (short for 'define'), followed by the function name, parentheses (), and a colon. The code that belongs to the function is indented underneath. The basic structure looks like this:

def function_name():
    print("Hello from the function")

The name should describe what the function does — use lowercase letters and underscores to separate words (e.g., 'calculate_total'). Once defined, you call (run) the function by writing its name followed by parentheses:

function_name()

This tells Python: "jump to the function definition, execute all the indented lines, then come back to where you were."

Now let's talk about parameters. Parameters are placeholders in the function definition that accept input values. They let the function work with different data each time it's called. When you define the function, you list parameter names inside the parentheses. For example:

def greet_user(username):
    print(f"Hello, {username}!")

Here, 'username' is a parameter. When you call the function, you provide an actual value, called an argument, that fills in that placeholder:

greet_user("Alice")

This passes the string "Alice" into the function, so 'username' holds "Alice" and the message prints "Hello, Alice!". You can have multiple parameters separated by commas.

Parameters give your functions flexibility. You can write one function that works with many different inputs, which saves you from writing separate functions for every possible value.

The 'return' statement is how a function sends a result back to the code that called it. Without 'return', the function runs its instructions but gives nothing back — it just prints to the screen or performs an action. With 'return', the function produces a value that you can store in a variable or use in an expression.

For example:

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

sum_value = add(3, 5)
print(sum_value)  # Outputs: 8

The 'return' statement immediately exits the function and gives back the value 'result' to the line that called it. You can only have one value returned (though it can be a complex data type like a list). Once Python hits a 'return' statement, it stops executing the rest of the function.

Why do functions exist? They solve several problems:

- They avoid code duplication (the DRY principle — Don't Repeat Yourself).
- They make code easier to read by giving a name to a block of logic.
- They make debugging easier — you can test one function at a time.
- They allow you to reuse code across different programs.

Before functions, you would have to copy and paste the same instructions everywhere, leading to huge, error-prone programs. Functions are a way to organise your code into logical, manageable chunks.

Here are the key rules to remember:

- The function body must be indented (by convention, 4 spaces).
- The 'def' line ends with a colon.
- Parameter names are local to the function — they don't exist outside it.
- If a function does not have a 'return' statement, it returns 'None' by default (Python's way of saying "nothing").
- You can call a function from anywhere after it's been defined — even from within other functions.

## Real-world context

Imagine you work for an online clothing store that needs to apply discounts to different orders. Your boss asks you to write a program that calculates the final price after a 10% discount on all items over $50. Without functions, you would write the same discount logic for every single item in your code — copying and pasting it dozens of times. Every time the discount rules change (say, to 15% for orders over $100), you would have to hunt down every copy and update it, inevitably missing some.

Instead, a professional IT developer writes a single function called 'apply_discount' that takes the original price and the discount percentage as parameters and returns the final price. Here is the step-by-step process of what happens in a real business scenario:

The development team starts by discussing the business rule: \"Apply a 10% discount on all items priced above $50.\" They translate this into a function:

def apply_discount(price, discount_percent):
    if price > 50:
        discounted_price = price - (price * discount_percent / 100)
        return discounted_price
    else:
        return price

Now, when the sales system receives an order, it calls this function for each item. For example:

item_price = 75
final_price = apply_discount(item_price, 10)
print(final_price)  # Outputs: 67.5

The function is tested in isolation — the QA team feeds it different prices (0, 50, 51, 200, -10) to ensure it handles edge cases correctly. Later, when the business changes the discount to 15% for orders over $100, the developer only needs to modify this one function, not every line of code that calculates a discount.

In a larger company, functions are often stored in separate files called modules, which can be imported into different programs. The 'apply_discount' function might be in a module called 'discounts.py', and the main shopping cart program imports it to use the same logic everywhere.

- Code reusability: The same function is called from the website checkout, the mobile app backend, and the admin panel.
- Testing: A function can be tested automatically with unit tests that verify it returns the correct values for known inputs.
- Collaboration: Different developers can work on different functions simultaneously without stepping on each other's code.

## Exam focus

The PCEP-30-02 exam tests your understanding of 'Defining and Calling Functions' in several specific ways. The exam is practical — you must write and read short Python code snippets, not just memorise theory. Here is exactly what you need to know:

The most common question type presents a short block of code with a function definition, followed by one or more function calls, and asks you to predict the output or determine if the code is valid. You will be given multiple-choice options with specific output values.

Exam topics include:

- Using the 'def' keyword correctly — recognising that the colon and indentation are essential.
- Calling a function by its name followed by parentheses — even if it has no parameters.
- Passing arguments to parameters — matching argument order to parameter order (positional arguments).
- Understanding that a function without 'return' returns 'None' automatically.
- Recognising that 'return' ends the function immediately — any code after 'return' is ignored.

Common traps the exam sets:

- They might show a function with 'return' inside a loop or 'if' statement and ask what the output is. Remember: the first 'return' executed stops the function.
- They might call a function with the wrong number of arguments (too many or too few), which causes a TypeError. The exam expects you to spot this invalid code.
- They might define a parameter but not call the function with an argument — the code defines it but never runs it, so no error occurs at definition time.
- They might use a variable name inside the function that also exists outside (global scope). The exam expects you to know that parameters and variables created inside a function are local and don't affect the outside world unless explicitly returned.

Key definitions to memorise:

- 'def': keyword to start a function definition.
- 'parameter': variable listed in the function definition that receives a value.
- 'argument': actual value passed to the function when calling it.
- 'return': statement that sends a value back to the caller and exits the function.
- 'None': the value a function returns if no 'return' statement is used.

The exam often asks trick questions about the difference between printing inside a function and returning a value. For example, a function that prints a calculation but returns nothing cannot be used in an assignment like 'x = my_func()' — x will hold 'None', not the printed value. You must distinguish between output (print) and result (return).

Practise predicting the output of nested function calls and simple arithmetic within functions. The exam rarely uses complex logic — focus on the fundamentals of defining, calling, parameters, and return.

## Step by step

1. **Define the function skeleton** — Start by writing 'def' followed by a meaningful name (like 'calculate_area') and parentheses. End the line with a colon. This tells Python you are about to create a reusable block of code. Indent the next lines by 4 spaces to indicate they belong to the function body.
2. **Add parameters inside the parentheses** — List any input values the function needs inside the parentheses, separated by commas. For example, 'def calculate_area(length, width):'. These parameter names are like blank boxes that will be filled with real values when the function is called. Without parameters, you can still define a function that needs no input.
3. **Write the function body** — Indented under the 'def' line, write the actual instructions Python should execute. This can include calculations, print statements, or any other valid Python code. The body runs every time the function is called. Be careful with indentation — incorrect indentation will cause an error.
4. **Use 'return' to send back a result (optional)** — If you want the function to produce a value that can be stored in a variable or used in an expression, include a 'return' statement followed by the value (or expression that evaluates to a value). This immediately exits the function and gives the value back to the caller. If you omit 'return', the function returns 'None'.
5. **Call the function from your code** — To execute the function, write its name followed by parentheses containing the actual arguments that match your parameters. Example: 'area = calculate_area(5, 3)'. Python will jump to the function definition, substitute 5 and 3 into 'length' and 'width', run the body, and then return control to the line after the call.

## Comparisons

### Parameter vs Argument

**Parameter:**
- Listed inside the parentheses of the function definition
- Acts as a placeholder or variable name for incoming data
- Exists only within the function's local scope

**Argument:**
- Written inside the parentheses of the function call
- The actual value that gets passed to the parameter
- Can be a literal value, variable, or expression

### return vs print

**return:**
- Sends a value back to the caller and exits the function
- The returned value can be stored in a variable or used in expressions
- If omitted, the function returns None by default

**print:**
- Outputs text to the console for the user to see
- Does not send a value back to the caller — returns None
- Used for showing information, not for reusing the result in code

### Function Definition vs Function Call

**Function Definition:**
- Uses 'def' keyword, a name, parameters, colon, and indented body
- Happens once in the code — defines what the function does
- Does not run the function's code; it only defines it

**Function Call:**
- Uses the function name followed by parentheses with arguments
- Can happen many times — runs the function's code each time
- Must come after the function definition in the code

### Local Variable (inside function) vs Global Variable (outside any function)

**Local Variable (inside function):**
- Created when the function runs and destroyed when it ends
- Cannot be accessed outside the function
- Does not affect variables with the same name outside

**Global Variable (outside any function):**
- Exists for the entire program execution
- Can be accessed from anywhere (including inside functions, but careful)
- Changes inside a function to a global require 'global' keyword (advanced)

## Diagram

_This flowchart shows the decision process for defining a function with 'def', adding parameters if needed, using 'return' to send back a result, and finally calling the function._

```mermaid
flowchart TD
    A[Start: Need to reuse code] --> B[Define function with 'def']
    B --> C{Does function need input?}
    C -->|Yes| D[Add parameters in parentheses]
    C -->|No| E[Use empty parentheses]
    D --> F[Write indented function body]
    E --> F
    F --> G{Do you need a result back?}
    G -->|Yes| H[Use 'return' with value]
    G -->|No| I[Function returns None automatically]
    H --> J[Call function with arguments]
    I --> J
    J --> K[Function runs and returns control]
```

## Common misconceptions

- **Misconception:** If a function has a 'return' statement, I must capture the returned value in a variable or the program will crash. **Reality:** You can call a function and ignore its return value completely — the program will run fine. The returned value is simply discarded if not assigned. (Beginners often think every return must be stored, but Python allows calling a function purely for its side effects (like printing).)
- **Misconception:** Defining a function with parameters means I must always provide exactly the same number of arguments when calling it later. **Reality:** Yes, for basic functions with positional parameters, the number of arguments must match the number of parameters. However, you can use default parameter values to make some arguments optional. (The exam only tests basic positional arguments, so beginners confuse this with later optional parameters they haven't learned yet.)
- **Misconception:** The 'return' keyword is optional and just makes the code look cleaner — the function will still give back a value without it. **Reality:** Without a 'return' statement, the function returns the special value 'None' every time. To send back a specific value (like a number or string), you must explicitly use 'return'. (Because beginners often see interactive environments printing function results and confuse that with returning.)
- **Misconception:** I can use the same variable name inside a function and outside the function, and they will always refer to the same value. **Reality:** Variables defined inside a function are local — they only exist while the function runs and do not affect variables with the same name outside the function. The function creates a separate namespace. (This is confusing because it feels like the same name should mean the same thing everywhere, but functions create isolated environments.)

## Key takeaways

- A function must be defined with the 'def' keyword, followed by a name, parentheses, and a colon, before it can be called. 
- Parameters act as placeholders inside the function that receive the values (arguments) you pass when calling it.
- The 'return' statement sends a value back to the caller and immediately exits the function — any code after 'return' is never executed.
- If a function does not contain a 'return' statement, it automatically returns the special value 'None'.
- Calling a function means writing its name followed by parentheses — if it expects parameters, you provide arguments inside those parentheses.
- Variables created inside a function are local to that function and cannot be accessed from outside unless they are returned.
- A function definition can appear anywhere in your code, but it must be defined before the line that calls it.
- The number of arguments in a function call must match the number of parameters in its definition (unless using optional defaults).

## FAQ

**What is the difference between a parameter and an argument?**

A parameter is the variable listed inside the function definition (for example, 'def greet(name):' — 'name' is the parameter). An argument is the actual value you pass when calling the function (for example, 'greet("Alice")' — "Alice" is the argument). The argument fills the parameter's placeholder.

**Can I have a function with no parameters?**

Yes, absolutely. Many functions perform a task that needs no outside input — for example, a function that prints a fixed welcome message. You define it as 'def welcome():' and call it as 'welcome()'. The parentheses are still required when calling, even if empty.

**What happens if I call a function with the wrong number of arguments?**

Python raises a TypeError. For example, if a function expects two parameters but you only provide one argument when calling it, Python will stop and show an error like "missing 1 required positional argument." The number of arguments must match the number of parameters (unless they have default values).

**What does a function return if there is no 'return' statement?**

It returns 'None' automatically. 'None' is a special value in Python that represents the absence of a value. For instance, if you write 'x = print("hello")', the variable 'x' will hold 'None' because the 'print' function does not return anything meaningful.

**Can I use a variable defined inside a function outside the function?**

No, not directly. Variables defined inside a function (including parameters) are local to that function — they are created when the function runs and destroyed when it finishes. To make a value available outside, you must use 'return' to send it back and assign it to a variable in the calling code.

**Do I have to define a function before I call it?**

Yes, Python reads code from top to bottom. If you call a function before defining it, Python will not know what it is and will raise a NameError. Always define all your functions at the top of your script (or in a separate module) before you call them.

## Check your understanding

1. **What keyword is used to define a function in Python?**

   Answer: The 'def' keyword is used to define a function.

2. **If a function does not have a 'return' statement, what value does it return when called?**

   Answer: It returns the special value 'None'.

3. **In the code 'def multiply(x, y):', what are 'x' and 'y' called?**

   Answer: They are called parameters.

4. **True or False: You can call a function that has been defined, even before the line where it is defined. **

   Answer: False. A function must be defined before it is called, because Python reads code from top to bottom.

5. **What happens if you write 'return' immediately inside a function with no value after it, like 'return'?**

   Answer: The function exits and returns 'None'.

---

Interactive version with quiz and diagrams: https://courseiva.com/learn/python-pcep/defining-and-calling-functions
