Lesson 4 of 34 · 0 of 3 exercises solved
Functions
are named, reusable blocks of code. They let you write logic once, call it from many places, and change it in one spot.
Define functions with the keyword. can have default values, and Python supports both positional and when calling functions.
# Basic function
def greet(name):
return f"Hello, {name}!"
print(greet("Alice")) # Hello, Alice!
# Default parameter values
def greet_with_title(name, title="Dr."):
return f"Hello, {title} {name}!"
print(greet_with_title("Smith")) # Hello, Dr. Smith!
print(greet_with_title("Jones", "Prof.")) # Hello, Prof. Jones!
# Multiple return values (returns a tuple)
def min_max(numbers):
return min(numbers), max(numbers)
lo, hi = min_max([3, 1, 4, 1, 5, 9, 2, 6])
print(lo, hi) # 1 9
# *args — variable number of arguments
def total(*args):
return sum(args)
print(total(1, 2, 3, 4)) # 10
# **kwargs — keyword arguments as a dict
def describe(**kwargs):
for key, value in kwargs.items():
print(f"{key}: {value}")
describe(name="Alice", age=30, city="Paris")functions are anonymous single-expression functions, useful for short operations passed to higher-order functions like sorted(), map(), and filter().
# Lambda: lambda parameters: expression
square = lambda x: x ** 2
print(square(5)) # 25
# Common use: sorting with a custom key
people = [("Alice", 30), ("Bob", 25), ("Charlie", 35)]
sorted_by_age = sorted(people, key=lambda p: p[1])
print(sorted_by_age) # [('Bob', 25), ('Alice', 30), ('Charlie', 35)]
# map() — apply function to every element
numbers = [1, 2, 3, 4, 5]
squares = list(map(lambda x: x**2, numbers))
print(squares) # [1, 4, 9, 16, 25]
# filter() — keep elements where function returns True
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4]Common question
Is a function worth writing if I only call it once?
A function is a named piece of work with defined inputs and a returned output. Its value is as much in the name as in reuse: it lets you think about a program in bigger chunks, test each chunk alone, and change how something works without touching the code that calls it. That is why experienced programmers pull out functions freely, including ones called from a single place.
The mechanics to remember are few. Parameters point at the caller's objects, so mutating them affects the caller and rebinding them does not. Default values are created once, when the function is defined. A function with no return gives back . Positional arguments come first, then keyword arguments, and *args and **kwargs collect any extras.
Source: Edsger Dijkstra: "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise."
Common mix-ups
Each of these sounds reasonable. Think about why it is wrong, then open the explanation.
Functions exist for reuse, so code used once should stay inline.
Function parameters are copies, so changing a inside a function is safe.
A default value like items=[] is created fresh on every call.
Practice
Write is_palindrome(text) that returns True when the text reads the same forwards and backwards, ignoring case and spaces. "Never odd or even" should count.
Palindrome checker
def is_palindrome(text):
# normalise, then compare with the reversed string
...
print(is_palindrome("racecar"))
print(is_palindrome("Never odd or even"))
print(is_palindrome("python"))
Press Run to try your code, then Check answer to grade it.Write average(*numbers) that accepts any number of arguments and returns their mean. With no arguments it should return 0 rather than crashing.
Variadic average
def average(*numbers):
...
print(average(2, 4, 6))
print(average())
Press Run to try your code, then Check answer to grade it.Write greet(name, greeting="Hello") that returns a like Hello, Ada! — and make it possible to change the greeting with a keyword argument.
Default and keyword arguments
def greet(name):
return "Hello, " + name
print(greet("Ada"))
print(greet("Grace", greeting="Good morning"))
Press Run to try your code, then Check answer to grade it.Check yourself
What does this function return when called as add_item("apple") twice in a row?
def add_item(item, basket=[]):
basket.append(item)
return basketTip: use the ← and → keys to move between lessons.