python-by-example/05_functions/04_lambda_functions.py
2025-12-30 08:50:00 +02:00

341 lines
10 KiB
Python

"""
================================================================================
File: 04_lambda_functions.py
Topic: Lambda Functions in Python
================================================================================
This file demonstrates lambda functions (anonymous functions) in Python.
Lambda functions are small, one-line functions that can be defined inline
without using the 'def' keyword.
Key Concepts:
- Lambda syntax
- When to use lambda functions
- Lambda with built-in functions (map, filter, sorted)
- Lambda vs regular functions
- Common use cases and patterns
================================================================================
"""
# -----------------------------------------------------------------------------
# 1. Basic Lambda Syntax
# -----------------------------------------------------------------------------
# lambda arguments: expression
print("--- Basic Lambda Syntax ---")
# Regular function
def add_regular(a, b):
return a + b
# Equivalent lambda function
add_lambda = lambda a, b: a + b
print(f"Regular function: {add_regular(3, 5)}")
print(f"Lambda function: {add_lambda(3, 5)}")
# More examples
square = lambda x: x ** 2
is_even = lambda x: x % 2 == 0
greet = lambda name: f"Hello, {name}!"
print(f"\nsquare(4) = {square(4)}")
print(f"is_even(7) = {is_even(7)}")
print(f"greet('Alice') = {greet('Alice')}")
# Lambda with no arguments
get_pi = lambda: 3.14159
print(f"get_pi() = {get_pi()}")
# -----------------------------------------------------------------------------
# 2. Lambda with Multiple Arguments
# -----------------------------------------------------------------------------
print("\n--- Multiple Arguments ---")
# Two arguments
multiply = lambda x, y: x * y
print(f"multiply(4, 5) = {multiply(4, 5)}")
# Three arguments
volume = lambda l, w, h: l * w * h
print(f"volume(2, 3, 4) = {volume(2, 3, 4)}")
# With default arguments
power = lambda base, exp=2: base ** exp
print(f"power(3) = {power(3)}") # 3^2 = 9
print(f"power(2, 3) = {power(2, 3)}") # 2^3 = 8
# -----------------------------------------------------------------------------
# 3. Lambda with Conditional Expression
# -----------------------------------------------------------------------------
# Using ternary operator in lambda
print("\n--- Conditional Lambda ---")
# Simple conditional
get_sign = lambda x: "positive" if x > 0 else ("negative" if x < 0 else "zero")
print(f"get_sign(5) = {get_sign(5)}")
print(f"get_sign(-3) = {get_sign(-3)}")
print(f"get_sign(0) = {get_sign(0)}")
# Max of two numbers
max_of_two = lambda a, b: a if a > b else b
print(f"\nmax_of_two(10, 20) = {max_of_two(10, 20)}")
# Absolute value
absolute = lambda x: x if x >= 0 else -x
print(f"absolute(-7) = {absolute(-7)}")
# -----------------------------------------------------------------------------
# 4. Lambda with map()
# -----------------------------------------------------------------------------
# Apply function to each element of iterable
print("\n--- Lambda with map() ---")
numbers = [1, 2, 3, 4, 5]
# Square each number
squares = list(map(lambda x: x ** 2, numbers))
print(f"Original: {numbers}")
print(f"Squared: {squares}")
# Convert to strings
strings = list(map(lambda x: str(x), numbers))
print(f"As strings: {strings}")
# Multiple iterables with map
list1 = [1, 2, 3]
list2 = [10, 20, 30]
sums = list(map(lambda x, y: x + y, list1, list2))
print(f"\n{list1} + {list2} = {sums}")
# Processing strings
names = ["alice", "bob", "charlie"]
capitalized = list(map(lambda name: name.capitalize(), names))
print(f"Capitalized: {capitalized}")
# -----------------------------------------------------------------------------
# 5. Lambda with filter()
# -----------------------------------------------------------------------------
# Filter elements based on condition
print("\n--- Lambda with filter() ---")
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# Filter even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"Original: {numbers}")
print(f"Even only: {evens}")
# Filter numbers greater than 5
greater_than_5 = list(filter(lambda x: x > 5, numbers))
print(f"Greater than 5: {greater_than_5}")
# Filter non-empty strings
strings = ["hello", "", "world", "", "python", ""]
non_empty = list(filter(lambda s: s, strings))
print(f"\nNon-empty strings: {non_empty}")
# Complex filtering
people = [
{"name": "Alice", "age": 25},
{"name": "Bob", "age": 17},
{"name": "Charlie", "age": 30},
{"name": "David", "age": 15}
]
adults = list(filter(lambda p: p["age"] >= 18, people))
print(f"Adults: {[p['name'] for p in adults]}")
# -----------------------------------------------------------------------------
# 6. Lambda with sorted()
# -----------------------------------------------------------------------------
# Custom sorting with key function
print("\n--- Lambda with sorted() ---")
# Sort by absolute value
numbers = [-5, 2, -1, 7, -3, 4]
by_absolute = sorted(numbers, key=lambda x: abs(x))
print(f"Original: {numbers}")
print(f"Sorted by absolute value: {by_absolute}")
# Sort strings by length
words = ["python", "is", "a", "programming", "language"]
by_length = sorted(words, key=lambda w: len(w))
print(f"\nSorted by length: {by_length}")
# Sort objects by attribute
students = [
{"name": "Alice", "grade": 85},
{"name": "Bob", "grade": 92},
{"name": "Charlie", "grade": 78}
]
by_grade = sorted(students, key=lambda s: s["grade"], reverse=True)
print(f"\nBy grade (highest first):")
for s in by_grade:
print(f" {s['name']}: {s['grade']}")
# Sort by multiple criteria
items = [("apple", 3), ("banana", 1), ("cherry", 2), ("apple", 1)]
# Sort by name, then by number
sorted_items = sorted(items, key=lambda x: (x[0], x[1]))
print(f"\nSorted by name, then number: {sorted_items}")
# -----------------------------------------------------------------------------
# 7. Lambda with reduce()
# -----------------------------------------------------------------------------
# Reduce iterable to single value
print("\n--- Lambda with reduce() ---")
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# Sum all numbers
total = reduce(lambda acc, x: acc + x, numbers)
print(f"Sum of {numbers} = {total}")
# Product of all numbers
product = reduce(lambda acc, x: acc * x, numbers)
print(f"Product of {numbers} = {product}")
# Find maximum
maximum = reduce(lambda a, b: a if a > b else b, numbers)
print(f"Maximum of {numbers} = {maximum}")
# Concatenate strings
words = ["Hello", " ", "World", "!"]
sentence = reduce(lambda a, b: a + b, words)
print(f"Concatenated: '{sentence}'")
# With initial value
numbers = [1, 2, 3]
sum_with_initial = reduce(lambda acc, x: acc + x, numbers, 100)
print(f"\nSum with initial 100: {sum_with_initial}")
# -----------------------------------------------------------------------------
# 8. Lambda in Data Processing
# -----------------------------------------------------------------------------
print("\n--- Data Processing Example ---")
# Sample data
transactions = [
{"id": 1, "type": "credit", "amount": 100},
{"id": 2, "type": "debit", "amount": 50},
{"id": 3, "type": "credit", "amount": 200},
{"id": 4, "type": "debit", "amount": 75},
{"id": 5, "type": "credit", "amount": 150}
]
# Filter credits only
credits = list(filter(lambda t: t["type"] == "credit", transactions))
print(f"Credit transactions: {len(credits)}")
# Extract amounts from credits
credit_amounts = list(map(lambda t: t["amount"], credits))
print(f"Credit amounts: {credit_amounts}")
# Total credits
total_credits = reduce(lambda acc, t: acc + t["amount"], credits, 0)
print(f"Total credits: ${total_credits}")
# Combined: total debits in one expression
total_debits = reduce(
lambda acc, x: acc + x,
map(
lambda t: t["amount"],
filter(lambda t: t["type"] == "debit", transactions)
),
0
)
print(f"Total debits: ${total_debits}")
# -----------------------------------------------------------------------------
# 9. Lambda vs Regular Functions
# -----------------------------------------------------------------------------
print("\n--- Lambda vs Regular Functions ---")
# Lambda: one expression, implicit return
# Regular: multiple statements, explicit return
# When to use LAMBDA:
# - Simple, one-line operations
# - As arguments to higher-order functions
# - When function won't be reused
# When to use REGULAR FUNCTIONS:
# - Multiple expressions/statements needed
# - Need docstrings
# - Function will be reused or tested
# - Complex logic
# Example: Complex logic needs regular function
def process_value(x):
"""Process value with multiple steps."""
# Step 1: Validate
if x < 0:
return None
# Step 2: Transform
result = x ** 2
# Step 3: Apply ceiling
if result > 100:
result = 100
return result
# This CAN'T be easily done with lambda
# lambda x: (None if x < 0 else min(x ** 2, 100)) # Gets messy
print(f"process_value(-5) = {process_value(-5)}")
print(f"process_value(5) = {process_value(5)}")
print(f"process_value(15) = {process_value(15)}")
# -----------------------------------------------------------------------------
# 10. Common Lambda Patterns
# -----------------------------------------------------------------------------
print("\n--- Common Lambda Patterns ---")
# 1. Default value getter
get_value = lambda d, key, default=None: d.get(key, default)
data = {"name": "John", "age": 30}
print(f"get_value: {get_value(data, 'name')}, {get_value(data, 'email', 'N/A')}")
# 2. Compose functions
compose = lambda f, g: lambda x: f(g(x))
add_one = lambda x: x + 1
double = lambda x: x * 2
add_then_double = compose(double, add_one)
print(f"add_then_double(5) = {add_then_double(5)}") # (5+1)*2 = 12
# 3. Partial application simulation
multiply_by = lambda n: lambda x: x * n
times_three = multiply_by(3)
print(f"times_three(7) = {times_three(7)}")
# 4. Key extractors for sorting
by_key = lambda key: lambda x: x[key]
products = [
{"name": "Apple", "price": 1.50},
{"name": "Banana", "price": 0.75},
{"name": "Cherry", "price": 2.00}
]
sorted_by_price = sorted(products, key=by_key("price"))
print(f"\nSorted by price: {[p['name'] for p in sorted_by_price]}")
# 5. Immediate invocation (IIFE-style)
result = (lambda x, y: x ** y)(2, 10)
print(f"\nImmediately invoked: 2^10 = {result}")