Defining Functions
def greet():
print("Hello, World!")
greet() # Hello, World!
Parameters and Arguments
def greet(name):
print(f"Hello, {name}!")
greet("Alice") # Hello, Alice!
greet("Bob") # Hello, Bob!
Return Values
def add(a, b):
return a + b
result = add(3, 5)
print(result) # 8
# Return multiple values (as a tuple):
def min_max(numbers):
return min(numbers), max(numbers)
lo, hi = min_max([3, 1, 4, 1, 5, 9])
print(lo, hi) # 1 9
Default Arguments
def power(base, exponent=2):
return base ** exponent
print(power(3)) # 9 (uses default exponent=2)
print(power(3, 3)) # 27
# Default mutable arguments โ GOTCHA!
def append_to(item, lst=[]): # BAD: shared across calls
lst.append(item)
return lst
def append_to_safe(item, lst=None): # GOOD
if lst is None:
lst = []
lst.append(item)
return lst
Keyword Arguments
def describe_pet(name, animal="dog"):
print(f"{name} is a {animal}")
describe_pet("Rex") # Rex is a dog
describe_pet("Whiskers", "cat") # Whiskers is a cat
describe_pet(animal="fish", name="Nemo") # Nemo is a fish
*args and **kwargs
# *args โ variable number of positional arguments
def total(*numbers):
return sum(numbers)
print(total(1, 2, 3, 4, 5)) # 15
# **kwargs โ variable number of keyword arguments
def user_info(**details):
for key, value in details.items():
print(f"{key}: {value}")
user_info(name="Alice", age=30, city="NYC")
# Combining all types:
def func(required, *args, default=10, **kwargs):
print(required, args, default, kwargs)
func(1, 2, 3, default=99, x="hello")
# 1 (2, 3) 99 {'x': 'hello'}
Keyword-Only and Positional-Only Arguments
# Keyword-only (after *)
def connect(host, *, port=80, ssl=False):
print(f"{host}:{port} ssl={ssl}")
connect("example.com", port=443, ssl=True)
# connect("example.com", 443) # TypeError!
# Positional-only (before /)
def circle_area(radius, /):
import math
return math.pi * radius ** 2
circle_area(5)
# circle_area(radius=5) # TypeError!
Docstrings
def factorial(n):
"""
Calculate the factorial of n.
Args:
n (int): Non-negative integer
Returns:
int: n! (n factorial)
Raises:
ValueError: If n is negative
"""
if n < 0:
raise ValueError("n must be non-negative")
if n == 0:
return 1
return n * factorial(n - 1)
help(factorial) # shows the docstring
Lambda Functions
square = lambda x: x ** 2
print(square(5)) # 25
# Common use with sorted, map, filter:
nums = [3, 1, 4, 1, 5, 9, 2, 6]
sorted_nums = sorted(nums, key=lambda x: -x) # descending
print(sorted_nums) # [9, 6, 5, 4, 3, 2, 1, 1]
pairs = [(1, 'b'), (3, 'a'), (2, 'c')]
pairs.sort(key=lambda p: p[1])
print(pairs) # [(3, 'a'), (1, 'b'), (2, 'c')]
Exercises
Exercise 1: Fibonacci
Write a function fibonacci(n) that returns the nth Fibonacci number (0-indexed).
Solution:
def fibonacci(n):
if n <= 0:
return 0
if n == 1:
return 1
a, b = 0, 1
for _ in range(2, n + 1):
a, b = b, a + b
return b
for i in range(10):
print(fibonacci(i), end=" ")
# 0 1 1 2 3 5 8 13 21 34
Exercise 2: Recursive Factorial
Write a recursive function for factorial.
Solution:
def factorial(n):
return 1 if n <= 1 else n * factorial(n - 1)
print(factorial(10)) # 3628800
Exercise 3: Flexible Calculator
Write a function calculate(operation, *numbers) supporting "add", "multiply", "max", "min".
Solution:
def calculate(operation, *numbers):
if operation == "add":
return sum(numbers)
elif operation == "multiply":
result = 1
for n in numbers:
result *= n
return result
elif operation == "max":
return max(numbers)
elif operation == "min":
return min(numbers)
else:
raise ValueError(f"Unknown operation: {operation}")
print(calculate("add", 1, 2, 3, 4)) # 10
print(calculate("multiply", 2, 3, 4)) # 24
print(calculate("max", 5, 3, 8, 1)) # 8