Lesson 13 of 25

Functions

Defining Functions and Parameters

A function is a reusable block of code that performs a specific task. You define a function using the 'def' keyword, followed by the function name, parentheses with optional parameters, and a colon.

Functions help you organize your code, avoid repetition, and make your programs easier to read and maintain.

Example
# Basic function
def greet():
    print("Hello, World!")

greet()  # Call the function

# Function with parameters
def greet_person(name):
    print(f"Hello, {name}!")

greet_person("Alice")  # Hello, Alice!

# Function with return value
def add(a, b):
    return a + b

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

# Default parameters
def greet_with_title(name, title="Mr."):
    print(f"Hello, {title} {name}!")

greet_with_title("Smith")           # Hello, Mr. Smith!
greet_with_title("Smith", "Dr.")    # Hello, Dr. Smith!

# Multiple return values
def min_max(numbers):
    return min(numbers), max(numbers)

low, high = min_max([3, 1, 7, 2, 9])
print(f"Min: {low}, Max: {high}")  # Min: 1, Max: 9
  • def function_name(parameters): — defines a function
  • return value — sends a value back to the caller
  • Default parameters have a fallback value if no argument is passed
  • Keyword arguments let you pass arguments by name: func(name='Alice')
  • Functions without a return statement implicitly return None
Try Creating Functions
JavaScript
def greet(name, greeting="Hello"):
    return f"{greeting}, {name}!"

print(greet("Alice"))
print(greet("Bob", "Hi"))

def calculate_area(length, width):
    return length * width

area = calculate_area(5, 3)
print(f"Area: {area}")
Notes
  • Function names should be descriptive and use snake_case. A function should ideally do one thing well — this is the Single Responsibility Principle.

*args and **kwargs

Sometimes you want a function to accept a flexible number of arguments. Python provides *args for variable positional arguments and **kwargs for variable keyword arguments.

*args collects extra positional arguments into a tuple, while **kwargs collects extra keyword arguments into a dictionary.

Example
# *args — variable number of positional arguments
def total(*args):
    print(f"Received: {args}")  # It's a tuple
    return sum(args)

print(total(1, 2, 3))        # 6
print(total(10, 20, 30, 40)) # 100

# **kwargs — variable number of keyword arguments
def print_info(**kwargs):
    for key, value in kwargs.items():
        print(f"{key}: {value}")

print_info(name="Alice", age=30, city="NYC")
# name: Alice
# age: 30
# city: NYC

# Combining regular params, *args, and **kwargs
def flexible(required, *args, **kwargs):
    print(f"Required: {required}")
    print(f"Extra args: {args}")
    print(f"Extra kwargs: {kwargs}")

flexible("hello", 1, 2, 3, color="red", size=10)
# Required: hello
# Extra args: (1, 2, 3)
# Extra kwargs: {'color': 'red', 'size': 10}
Try *args and **kwargs
JavaScript
def total(*args):
    return sum(args)

print("Sum:", total(1, 2, 3, 4, 5))

def build_profile(**kwargs):
    for key, value in kwargs.items():
        print(f"  {key}: {value}")

print("Profile:")
build_profile(name="Alice", age=30, role="Developer")
Notes
  • The names 'args' and 'kwargs' are conventions, not requirements. The special syntax is the * and ** prefixes. You could use *numbers or **options if those names are more descriptive.