DocsHub
Functions

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 argument

A 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)   # 15

The 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   # 35

Without return:

def add(a, b):
    print(a + b)    # prints but returns nothing

result = add(3, 4)
print(result)       # None

The 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)   # 9

Python 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 + b

You 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))   # 25

sum_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.0

Each function does one job. They are small, readable, and reusable.


Summary

ConceptExample
Define a functiondef greet():
Call a functiongreet()
ParameterVariable in the definition
ArgumentValue passed when calling
Return a valuereturn result
Return multiple valuesreturn a, b
Docstring"""Explains the function."""

On this page