</>
Skip to content
Python lessons (21/45)

Python — Functions

Defining functions

Functions are reusable blocks of code that perform a specific task:

def greet(name):
    print(f"Hello, {name}!")

greet("Ada")    # Hello, Ada!
greet("Grace")  # Hello, Grace!

Functions start with def, followed by a name, parameters in parentheses, and a colon. The body is indented.

Parameters and arguments

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

result = add(3, 7)
print(result)  # 10
  • Parameters are the variables in the function definition: a, b
  • Arguments are the values passed when calling: 3, 7

Return values

Use return to send a value back:

def square(x):
    return x ** 2

print(square(5))  # 25

A function without return returns None implicitly:

def greet(name):
    print(f"Hello, {name}!")

result = greet("Ada")  # prints greeting
print(result)          # None

Default parameters

def greet(name, greeting="Hello"):
    print(f"{greeting}, {name}!")

greet("Ada")              # Hello, Ada!
greet("Ada", "Hey")       # Hey, Ada!
greet("Ada", greeting="Hi")  # Hi, Ada!

Default values make parameters optional. Put required parameters first.

Keyword arguments

def create_user(name, age, email):
    return {"name": name, "age": age, "email": email}

# Positional
user1 = create_user("Ada", 36, "ada@example.com")

# Keyword — order doesn't matter
user2 = create_user(age=30, email="bob@example.com", name="Bob")

Keyword arguments make function calls readable and order-independent.

Multiple return values

def get_stats(numbers):
    return min(numbers), max(numbers), sum(numbers) / len(numbers)

low, high, avg = get_stats([3, 1, 4, 1, 5, 9])
print(f"Min: {low}, Max: {high}, Avg: {avg:.1f}")

Python returns a tuple automatically. Destructure at the call site.

*args and **kwargs

For functions that accept any number of arguments:

# *args — positional arguments as a tuple
def add_all(*args):
    return sum(args)

print(add_all(1, 2, 3, 4, 5))  # 15

# **kwargs — keyword arguments as a dict
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Ada", age=36, job="Engineer")

*args collects extra positional arguments. **kwargs collects extra keyword arguments.

Scope — LEGB rule

Python looks up variables in this order:

  1. Local — inside the function
  2. Enclosing — in the outer function (for nested functions)
  3. Global — at the module level
  4. Built-in — Python's built-in names
x = "global"

def outer():
    x = "enclosing"

    def inner():
        x = "local"
        print(x)  # local

    inner()
    print(x)  # enclosing

outer()
print(x)  # global

Modifying global variables

counter = 0

def increment():
    global counter
    counter += 1

increment()
print(counter)  # 1

Avoid global when possible. Pass values as parameters and return results instead.

Nested functions

def make_multiplier(factor):
    def multiply(number):
        return number * factor
    return multiply

double = make_multiplier(2)
triple = make_multiplier(3)

print(double(5))   # 10
print(triple(5))   # 15

This is a closure — the inner function remembers the outer function's variables even after the outer function returns.

Docstrings

def calculate_bmi(weight, height):
    """
    Calculate Body Mass Index (BMI).

    Args:
        weight: Weight in kilograms.
        height: Height in meters.

    Returns:
        BMI as a float.
    """
    return weight / (height ** 2)

Docstrings describe what a function does, its parameters, and return value. Access them with help(calculate_bmi).

Type hints

def add(a: int, b: int) -> int:
    return a + b

def greet(name: str) -> str:
    return f"Hello, {name}!"

Type hints don't enforce types at runtime but help editors and tools like mypy catch bugs.

Lambda functions

Anonymous functions for short operations:

square = lambda x: x ** 2
print(square(5))  # 25

add = lambda a, b: a + b
print(add(3, 7))  # 10

Lambdas are limited to single expressions. Use them where a small function is needed temporarily:

numbers = [3, 1, 4, 1, 5, 9]
sorted_numbers = sorted(numbers, key=lambda x: -x)
print(sorted_numbers)  # [9, 5, 4, 3, 1, 1]

Common patterns

Functions as arguments

def apply(func, value):
    return func(value)

print(apply(str.upper, "hello"))  # HELLO
print(apply(len, "hello"))        # 5

Decorators

def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        print(f"{func.__name__} took {time.time() - start:.4f}s")
        return result
    return wrapper

@timer
def slow_function():
    import time
    time.sleep(1)

slow_function()  # prints execution time

Mini Practice

  1. Write a function that takes a list and returns a new list with only even numbers
  2. Create a function with default parameters for a greeting message
  3. Write a function that returns multiple values: min, max, and average
  4. Use a lambda with sorted() to sort a list of dictionaries by a specific key
  5. Write a decorator that logs when a function is called

Next: lambda expressions →

Related Topics

Frequently Asked Questions about Functions

What is Functions in Python?

Functions is a fundamental concept in Python. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Functions?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Functions.

Why is Functions important in Python?

Functions is essential for Python development. Understanding this concept will help you write better code and solve real-world problems more effectively.