Defining Functions
Learn how to write reusable blocks of code in Python using functions.
Defining Functions
A function is a named, reusable block of code that performs a specific task. Instead of writing the same code in multiple places, you write it once inside a function and call it by name whenever you need it.
Think of a function like a machine. You feed it some input, it does its job, and it gives you back an output. You do not need to know how the machine works inside — you just use it.
def greet(name):
return f"Hello, {name}!"
print(greet("Ali")) # Hello, Ali!
print(greet("Sara")) # Hello, Sara!You wrote the logic once. You used it twice. That is the whole point.
Why use functions?
Without functions, code gets repeated, hard to read, and painful to fix:
# Without functions — repeated logic everywhere
print(f"Hello, Ali! Welcome.")
print(f"Hello, Sara! Welcome.")
print(f"Hello, Omar! Welcome.")If you wanted to change "Welcome" to "Good to see you", you would change it in three places. In a real program, maybe three hundred places.
With a function:
def greet(name):
print(f"Hello, {name}! Good to see you.")
greet("Ali")
greet("Sara")
greet("Omar")Change it in one place — it updates everywhere. This principle is called DRY — Don't Repeat Yourself.
Defining a function
Use the def keyword, give it a name, add parentheses, and end with a colon. The code inside must be indented.
def say_hello():
print("Hello!")This defines the function — it does not run it yet. To run it, you call it by name:
say_hello() # Hello!Parameters and arguments
A parameter is the variable name inside the function definition. An argument is the actual value you pass when calling the function.
def greet(name): # 'name' is the parameter
print(f"Hello, {name}!")
greet("Ali") # "Ali" is the argumentA function can take multiple parameters:
def introduce(name, age, city):
print(f"My name is {name}, I am {age} years old, from {city}.")
introduce("Ali", 22, "Lahore")
# My name is Ali, I am 22 years old, from Lahore.return — giving back a value
return sends a value back to wherever the function was called. Without return, the function does its job and gives back None.
def add(a, b):
return a + b
result = add(10, 5)
print(result) # 15The returned value can be stored in a variable, printed, or used directly in an expression:
print(add(3, 4)) # 7
total = add(10, 20) + 5 # 35Without return:
def add(a, b):
print(a + b) # prints but returns nothing
result = add(3, 4)
print(result) # NoneThe function printed 7 but returned None — so result is None. This is a common beginner mistake — confusing printing inside a function with returning a value.
print() and return are not the same thing. print() shows something on screen. return sends a value back to the caller. If you want to use the result later, always use return.
return exits the function immediately
As soon as Python hits a return, it leaves the function. Any code after it in the same block does not run.
def check_age(age):
if age < 0:
return "Invalid age."
if age < 18:
return "Minor."
return "Adult."
print(check_age(-1)) # Invalid age.
print(check_age(15)) # Minor.
print(check_age(25)) # Adult.Each return exits immediately — only one of the three ever runs per call.
Returning multiple values
Python lets you return more than one value. They come back as a tuple:
def min_max(numbers):
return min(numbers), max(numbers)
lowest, highest = min_max([4, 1, 9, 2, 7])
print(lowest) # 1
print(highest) # 9Python packs the two values into a tuple on return, then unpacks them into lowest and highest. Clean and readable.
Docstrings — documenting your function
A docstring is a string written on the first line inside a function that explains what it does. Use triple quotes.
def add(a, b):
"""
Returns the sum of two numbers.
Parameters:
a: first number
b: second number
Returns:
Sum of a and b
"""
return a + bYou can read a function's docstring with help() or __doc__:
print(add.__doc__)
help(add)Docstrings are not required for small personal scripts — but they are essential when writing code others will read or use. Get into the habit early.
Good function names reduce the need for comments. A function called calculate_total_price() tells you exactly what it does. A function called calc() tells you nothing.
Functions calling other functions
Functions can call other functions. This is how you break a big problem into small, manageable pieces:
def square(n):
return n * n
def sum_of_squares(a, b):
return square(a) + square(b)
print(sum_of_squares(3, 4)) # 25sum_of_squares does not care how square works internally — it just uses it. This is the foundation of clean, organized code.
A real example
A simple checkout system:
def calculate_discount(price, percent):
"""Returns the discounted price."""
discount = price * (percent / 100)
return price - discount
def calculate_tax(price, tax_rate):
"""Returns the price with tax added."""
return price + (price * tax_rate / 100)
def final_price(price, discount_percent, tax_rate):
"""Returns the final price after discount and tax."""
after_discount = calculate_discount(price, discount_percent)
after_tax = calculate_tax(after_discount, tax_rate)
return round(after_tax, 2)
print(final_price(1000, 10, 15)) # 1035.0Each function does one job. They are small, readable, and reusable.
Summary
| Concept | Example |
|---|---|
| Define a function | def greet(): |
| Call a function | greet() |
| Parameter | Variable in the definition |
| Argument | Value passed when calling |
| Return a value | return result |
| Return multiple values | return a, b |
| Docstring | """Explains the function.""" |