Functions in Python

A function is a reusable, named block of code that performs a specific task. Functions let you avoid repeating the same logic throughout a program, and they make code easier to read, test, and maintain.

Defining a Function

A function is created with the def keyword, followed by a name, parentheses for parameters, and a colon. The code inside the function must be indented. The return keyword sends a value back to wherever the function was called.

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

result = add(5, 3)
print(result)   # 8

Here, a and b are the function's parameters, while 5 and 3 are the arguments passed in when the function is called. If a function has no return statement, it returns None by default.

Default Parameter Values

A parameter can be given a default value, which is used automatically whenever the caller does not supply that argument.

def greet(name="World"):
    print("Hello,", name)

greet()          # Hello, World  - uses the default
greet("Alice")   # Hello, Alice  - overrides the default

Keyword Arguments vs Positional Arguments

Arguments can be passed by position (matched to parameters in order) or by keyword (matched by parameter name, in any order). Keyword arguments make calls more readable, especially for functions with several parameters.

def describe_pet(name, animal_type):
    print(name, "is a", animal_type)

# positional - order matters
describe_pet("Rex", "dog")

# keyword - order does not matter
describe_pet(animal_type="cat", name="Whiskers")

Variable-Length Arguments: *args and **kwargs

Sometimes the number of arguments a function should accept is not known in advance. *args collects any number of extra positional arguments into a tuple, and **kwargs collects any number of extra keyword arguments into a dictionary.

# *args example - accepts any number of positional arguments
def total(*args):
    print(type(args))   # <class 'tuple'>
    return sum(args)

print(total(1, 2, 3, 4))   # 10

# **kwargs example - accepts any number of keyword arguments
def show_profile(**kwargs):
    print(type(kwargs))   # <class 'dict'>
    for key, value in kwargs.items():
        print(key, ":", value)

show_profile(name="Alice", age=30, city="Delhi")
# name : Alice
# age : 30
# city : Delhi

Docstrings

A docstring is a string literal placed immediately after the function signature, used to document what the function does. It is written using triple quotes and can be read later using help() or the function's .__doc__ attribute.

def square(number):
    """Return the square of the given number."""
    return number * number

print(square.__doc__)   # Return the square of the given number.

Variable Scope

A variable created inside a function is local to that function and cannot be accessed outside it. A variable created outside any function is global and can be read from inside a function, but not modified there unless it is explicitly declared with the global keyword.

count = 0   # global variable

def show_count():
    print(count)   # reading a global variable is fine

def increment():
    global count   # required to modify the global variable
    count = count + 1

show_count()    # 0
increment()
show_count()    # 1

A Full Worked Example

The function below combines a default parameter, *args, **kwargs, and a docstring in one place.

def build_report(title, *scores, passing=40, **details):
    """Build a simple text report from a title, any number of scores,
    a passing threshold, and any number of extra details."""
    average = sum(scores) / len(scores)
    result = "Pass" if average >= passing else "Fail"

    print("Report:", title)
    print("Average score:", average)
    print("Result:", result)

    for key, value in details.items():
        print(key, ":", value)

build_report("Term 1", 72, 65, 80, passing=50, student="Alice", grade="10th")
# Report: Term 1
# Average score: 72.33333333333333
# Result: Pass
# student : Alice
# grade : 10th
Next steps: Head to Lambda Functions to learn how to write short, anonymous functions.