← View series: python tutorials
~/blog
Functions - Advanced
Introduction
In this tutorial, you'll learn advanced function concepts in Python: lambda functions, *args and **kwargs, decorators, and more. These techniques will help you write more powerful and flexible code.
What You'll Learn
- Lambda functions (anonymous functions)
- *args and **kwargs
- Decorators
- Function composition
- Map, filter, and reduce
Lambda Functions
Lambda functions are small, anonymous functions defined in a single line. They're useful when you need a simple function for a short period.
Basic Lambda
# Regular function
def square(x):
return x ** 2
# Lambda equivalent
square = lambda x: x ** 2
print(square(5)) # 25Lambda Syntax
# lambda parameters: expressionLambda with Multiple Parameters
# Addition
add = lambda a, b: a + b
print(add(3, 5)) # 8
# Full name
full_name = lambda first, last: f"{first} {last}"
print(full_name("John", "Doe")) # John DoeWhen to Use Lambda
Lambda functions are commonly used with built-in functions like map(), filter(), and sorted():
# With map() - apply function to each item
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# With sort() - using a key function
names = ["Alice", "Bob", "Charlie", "David"]
# Sort by length
sorted_names = sorted(names, key=lambda x: len(x))
print(sorted_names) # ['Bob', 'Alice', 'David', 'Charlie']*args and **kwargs
These special parameters allow functions to accept variable numbers of arguments.
*args - Variable Positional Arguments
def sum_all(*args):
print(f"args type: {type(args)}")
return sum(args)
print(sum_all(1, 2, 3)) # 6
print(sum_all(1, 2, 3, 4, 5)) # 15
print(sum_all()) # 0**kwargs - Variable Keyword Arguments
def print_info(**kwargs):
print(f"kwargs type: {type(kwargs)}")
for key, value in kwargs.items():
print(f"{key}: {value}")
print_info(name="Alice", age=25)
# name: Alice
# age: 25Combining All
def flexible_function(required, *args, **kwargs):
print(f"Required: {required}")
print(f"Args: {args}")
print(f"Kwargs: {kwargs}")
flexible_function("hello", 1, 2, 3, name="Alice", age=25)Output:
Required: hello
Args: (1, 2, 3)
_kwargs: {'name': 'Alice', 'age': 25}
Practical Example
def calculate_stats(operation, *numbers):
if operation == "sum":
return sum(numbers)
elif operation == "average":
return sum(numbers) / len(numbers) if numbers else 0
elif operation == "max":
return max(numbers) if numbers else None
elif operation == "min":
return min(numbers) if numbers else None
print(calculate_stats("sum", 1, 2, 3, 4, 5)) # 15
print(calculate_stats("average", 10, 20, 30)) # 20.0
print(calculate_stats("max", 3, 1, 4, 1, 5)) # 5Decorators
Decorators are functions that modify the behavior of other functions. They're a powerful way to add functionality without modifying the original function.
Basic Decorator
def my_decorator(func):
def wrapper():
print("Before function call")
func()
print("After function call")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()Output:
Before function call
Hello!
After function call
Decorator with Arguments
def repeat(times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Alice")Output:
Hello, Alice!
Hello, Alice!
Hello, Alice!
Practical Decorator Example
import time
def timer(func):
"""Decorator to measure execution time"""
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} took {end - start:.4f} seconds")
return result
return wrapper
@timer
def slow_function():
time.sleep(1)
print("Function completed!")
slow_function()Multiple Decorators
def decorator1(func):
def wrapper():
print("Decorator 1 - Before")
func()
print("Decorator 1 - After")
return wrapper
def decorator2(func):
def wrapper():
print("Decorator 2 - Before")
func()
print("Decorator 2 - After")
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()Output:
Decorator 1 - Before
Decorator 2 - Before
Hello!
Decorator 2 - After
Decorator 1 - After
Map, Filter, and Reduce
These are functional programming tools for processing collections.
map() - Apply Function to All Items
# Square all numbers
numbers = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x ** 2, numbers))
print(squared) # [1, 4, 9, 16, 25]
# Convert to uppercase
words = ["hello", "world"]
upper = list(map(str.upper, words))
print(upper) # ['HELLO', 'WORLD']filter() - Keep Items Meeting Condition
# Keep even numbers
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(evens) # [2, 4, 6, 8, 10]
# Keep words with length > 4
words = ["cat", "elephant", "dog", "hippopotamus"]
long_words = list(filter(lambda x: len(x) > 4, words))
print(long_words) # ['elephant', 'hippopotamus']reduce() - Accumulate Values
from functools import reduce
# Sum all numbers
numbers = [1, 2, 3, 4, 5]
total = reduce(lambda x, y: x + y, numbers)
print(total) # 15
# Find maximum
maximum = reduce(lambda x, y: x if x > y else y, numbers)
print(maximum) # 5
# Multiply all numbers
product = reduce(lambda x, y: x * y, numbers)
print(product) # 120Function Composition
Combining simple functions to build complex operations:
def compose(f, g):
"""Compose two functions: f(g(x))"""
return lambda x: f(g(x))
# Example
add_one = lambda x: x + 1
double = lambda x: x * 2
# Create composed function
add_one_then_double = compose(double, add_one)
print(add_one_then_double(5)) # 12 ( (5+1) * 2 )Summary
In this tutorial, you learned:
- ✅ Lambda functions (anonymous functions)
- ✅ *args for variable positional arguments
- ✅ **kwargs for variable keyword arguments
- ✅ Decorators and how to create them
- ✅ Map, filter, and reduce functions
- ✅ Function composition
🧑💻 Practice Exercise
Create a program that:
- Has a decorator that logs function calls (prints "Calling [function name]")
- Has a function that accepts *args and calculates sum and product
- Uses lambda with map/filter to process a list of numbers
Click to see solution
# Decorator to log function calls
def logger(func):
def wrapper(*args, **kwargs):
print(f"Calling {func.__name__}")
result = func(*args, **kwargs)
print(f"{func.__name__} returned {result}")
return result
return wrapper
@logger
def calculate_sum(*numbers):
"""Calculate sum of all numbers"""
return sum(numbers)
@logger
def calculate_product(*numbers):
"""Calculate product of all numbers"""
result = 1
for num in numbers:
result *= num
return result
# Test the functions
print("=== Sum ===")
total = calculate_sum(1, 2, 3, 4, 5)
print("\n=== Product ===")
product = calculate_product(1, 2, 3, 4, 5)
# Using lambda with map and filter
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Square all numbers
squared = list(map(lambda x: x ** 2, numbers))
print(f"\nSquared: {squared}")
# Keep only even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"Evens: {evens}")
# Even numbers squared
even_squared = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, numbers)))
print(f"Even squared: {even_squared}")Output:
=== Sum
Calling calculate_sum
calculate_sum returned 15
=== Product
Calling calculate_product
calculate_product returned 120
Squared: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Evens: [2, 4, 6, 8, 10]
Even squared: [4, 16, 36, 64, 100]
What's Next
In the next tutorial, we'll learn about Modules & Packages - how to organize and reuse code across files.