Have you ever been in a situation where you have to do the same task repetitively?
It can be tiresome right?
We often find ourselves in similar situations when writing code. For example, when you are required to calculate a value three different times in the same program. You have the option of copying and pasting twenty lines of code, modifying a single variable name, and crossing your fingers that you didn't introduce a typo, or... use loops and functions.
Check my article on How Python Loops Actually Work: A Hands-On Guide with Real Projects
A function is simply a packaged block of reusable code designed to perform a single task. Instead of rewriting instructions over and over, you write them once, give that package a name, and run it whenever you need it.
Defining and Calling a Function
Creating a function in Python requires the def keyword, followed by a name, parentheses, and a colon. The indented lines underneath form the body of the function.
def greet():
print("Welcome back!")
Defining a function does not run it. It only teaches Python what the function does. To execute that logic, you must call it by writing its name followed by parentheses:
greet() # Output: Welcome back!
If you leave off the parentheses, Python will not run the code; it will simply tell you that the name refers to a function object in memory.
Inputs: Parameters vs. Arguments
Most functions need data to do meaningful work. We pass data into functions using parameters and arguments. People often use these two terms interchangeably, but there is a clear distinction:
- Parameters are the placeholder variable names listed in the function definition (subtotal and tax_rate in the program below).
- Arguments are the actual values passed into the function when you call it (100, 0.20 in the program below).
def calculate_tax(subtotal, tax_rate=0.16):
total = subtotal * (1 + tax_rate)
print(f"Total with tax: ${total:.2f}")
calculate_tax(100) # Uses the default tax_rate of 0.16
calculate_tax(100, 0.20) # Overrides tax_rate with 0.20
Notice tax_rate=0.16. That is a default parameter. It allows the caller to omit that argument unless they specifically need a different rate.
Returning Values vs. Printing
Beginners often confuse print() with return.
A print() statement merely displays text in your terminal for human eyes. It does not hand data back to your program. The return statement, on the other hand, ends the function and sends data back to the line of code that called it, letting you store that output in a variable.
def add(a, b):
return a + b
result = add(4, 6)
# result now holds the integer 10, which we can use anywhere else
print(result * 2) # Output: 20
If a function finishes without encountering a return statement, Python silently returns None.
Variable Scope: Local vs. Global
Scope dictates where a variable can be seen and used.
Variables created inside a function are local. They exist only while that function is running and disappear the moment it finishes.
def set_discount():
discount = 15 # Local variable
return discount
set_discount()
# print(discount) # Raises NameError: name 'discount' is not defined
Variables created outside functions in your main script are global. While functions can read global variables, modifying them inside a function requires extra care.
As a best practice, avoid relying on global state inside functions. Pass what the function needs through arguments, and get results back using
return. This keeps your code predictable and easy to debug.
Practical Example: A Simple Order Processor
Here is a realistic pattern showing how small, focused functions work together to process an e-commerce order:
def calculate_subtotal(prices):
return sum(prices)
def apply_coupon(amount, code):
if code == "SAVE10":
return amount * 0.90
return amount
def finalize_order(cart_prices, coupon_code=""):
subtotal = calculate_subtotal(cart_prices)
discounted = apply_coupon(subtotal, coupon_code)
final_total = round(discounted, 2)
return {
"items_count": len(cart_prices),
"final_total": final_total
}
# Running the workflow
cart = [1000, 5000, 2500]
order_summary = finalize_order(cart, "SAVE10")
print(f"Items: {order_summary['items_count']}")
print(f"Total Due: Ksh. {order_summary['final_total']}")
Notice how finalize_order does not calculate the sum or discount itself. It coordinates smaller helper functions. If tax or coupon logic changes later, you update only one isolated block of code.
Common Mistakes to Watch Out For
-
Modifying a mutable default argument: Writing
def add_item(item, basket=[])leads to strange bugs. Python creates that list once when the function is defined, meaning the same list persists across every call. Usebasket=Noneinstead and initialize an empty list inside. -
Forgetting to return: If your calculations vanish and variables print as
None, check whether you ended your function withreturn. - Writing functions that do too much: If a single function fetches data, validates it, formats it, and prints it, break it up. Aim for functions that do one thing well.
Next Steps
Functions turn scripts into clean, modular programs. The easiest way to get comfortable with them is to take a script you have already written, identify sections where you repeated logic, and extract those lines into their own functions. Once you can pass arguments in and return values out, larger Python projects become significantly easier to reason about and maintain.
Top comments (0)