Functions & Scope
Lambda
Anonymous Functions
You need to sort users by age. Writing a separate get_age() function feels
like overkill for one use. Lambda lets you define small functions inline:
sorted(users, key=lambda u: u.age).
Basic lambda syntax
Create a small anonymous function.
def main():
print("=== Basic Lambda ===\n")
# Regular function
def square(x):
return x * x
# Lambda equivalent
square_lambda = lambda x: x * x
# Both work the same!
print(f"square(5) = {square(5)}")
print(f"square_lambda(5) = {square_lambda(5)}")
print("\n=== Lambda Syntax ===")
# lambda arguments: expression
add = lambda a, b: a + b
multiply = lambda a, b: a * b
print(f"add(3, 4) = {add(3, 4)}")
print(f"multiply(3, 4) = {multiply(3, 4)}")
print("\n=== Inline Usage (Most Common) ===")
numbers = [1, 2, 3, 4, 5]
# Lambda used directly, not assigned
squared = list(map(lambda x: x ** 2, numbers))
print(f"Squares of {numbers}: {squared}")
print("\n=== Type Comparison ===")
print(f"type(square): {type(square)}")
print(f"type(square_lambda): {type(square_lambda)}")
print(f"square.__name__: '{square.__name__}'")
print(f"square_lambda.__name__: '{square_lambda.__name__}'") # <lambda>
if __name__ == "__main__":
main()
lambda x: x * 2 is equivalent to def f(x): return x * 2.
Lambda as sort key
Use lambda to customize sorting.
def main():
print("=== Lambda as Sort Key ===\n")
# Sort strings by length
words = ["apple", "pie", "banana", "kiwi"]
print(f"Original: {words}")
sorted_by_length = sorted(words, key=lambda w: len(w))
print(f"By length: {sorted_by_length}")
print("\n=== Sort Objects by Attribute ===")
people = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35}
]
# Sort by age
by_age = sorted(people, key=lambda p: p["age"])
print("By age:")
for person in by_age:
print(f" {person['name']}: {person['age']}")
# Sort by name
by_name = sorted(people, key=lambda p: p["name"])
print("\nBy name:")
for person in by_name:
print(f" {person['name']}: {person['age']}")
print("\n=== Reverse Sort ===")
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
descending = sorted(numbers, key=lambda x: -x)
print(f"Descending: {descending}")
# Or use reverse=True
descending2 = sorted(numbers, reverse=True)
print(f"With reverse=True: {descending2}")
print("\n=== Complex Sort Key ===")
students = [
("Alice", 85, 22),
("Bob", 90, 20),
("Charlie", 85, 21)
]
# Sort by grade (desc), then age (asc)
sorted_students = sorted(students, key=lambda s: (-s[1], s[2]))
print("By grade (desc), then age (asc):")
for name, grade, age in sorted_students:
print(f" {name}: grade={grade}, age={age}")
if __name__ == "__main__":
main()
sorted(items, key=lambda x: x.attr) sorts by any attribute or computation.
Lambda with filter and map
Transform and filter collections inline.
def main():
print("=== Lambda with filter() ===\n")
numbers =
print(f"Numbers: {numbers}")
# Filter positive numbers
positives = list(filter(lambda x: x > 0, numbers))
print(f"Positives: {positives}")
# Filter even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"Evens: {evens}")
print("\n=== Lambda with map() ===")
# Square each number
squared = list(map(lambda x: x ** 2, numbers))
print(f"Squared: {squared}")
# Absolute value
absolutes = list(map(lambda x: abs(x), numbers))
print(f"Absolutes: {absolutes}")
print("\n=== Combining filter and map ===")
# Square of positive numbers only
result = list(map(lambda x: x ** 2,
filter(lambda x: x > 0, numbers)))
print(f"Squares of positives: {result}")
print("\n=== List Comprehension Alternative ===")
# Often clearer than map/filter!
positives_comp = [x for x in numbers if x > 0]
print(f"Positives (comprehension): {positives_comp}")
squared_comp = [x ** 2 for x in numbers]
print(f"Squared (comprehension): {squared_comp}")
combined_comp = [x ** 2 for x in numbers if x > 0]
print(f"Squares of positives (comprehension): {combined_comp}")
if __name__ == "__main__":
main()
def main():
print("=== Lambda with filter() ===\n")
numbers =
print(f"Numbers: {numbers}")
# Filter positive numbers
positives = list(filter(lambda x: x > 0, numbers))
print(f"Positives: {positives}")
# Filter even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"Evens: {evens}")
print("\n=== Lambda with map() ===")
# Square each number
squared = list(map(lambda x: x ** 2, numbers))
print(f"Squared: {squared}")
# Absolute value
absolutes = list(map(lambda x: abs(x), numbers))
print(f"Absolutes: {absolutes}")
print("\n=== Combining filter and map ===")
# Square of positive numbers only
result = list(map(lambda x: x ** 2,
filter(lambda x: x > 0, numbers)))
print(f"Squares of positives: {result}")
print("\n=== List Comprehension Alternative ===")
# Often clearer than map/filter!
positives_comp = [x for x in numbers if x > 0]
print(f"Positives (comprehension): {positives_comp}")
squared_comp = [x ** 2 for x in numbers]
print(f"Squared (comprehension): {squared_comp}")
combined_comp = [x ** 2 for x in numbers if x > 0]
print(f"Squares of positives (comprehension): {combined_comp}")
if __name__ == "__main__":
main()
def main():
print("=== Lambda with filter() ===\n")
numbers =
print(f"Numbers: {numbers}")
# Filter positive numbers
positives = list(filter(lambda x: x > 0, numbers))
print(f"Positives: {positives}")
# Filter even numbers
evens = list(filter(lambda x: x % 2 == 0, numbers))
print(f"Evens: {evens}")
print("\n=== Lambda with map() ===")
# Square each number
squared = list(map(lambda x: x ** 2, numbers))
print(f"Squared: {squared}")
# Absolute value
absolutes = list(map(lambda x: abs(x), numbers))
print(f"Absolutes: {absolutes}")
print("\n=== Combining filter and map ===")
# Square of positive numbers only
result = list(map(lambda x: x ** 2,
filter(lambda x: x > 0, numbers)))
print(f"Squares of positives: {result}")
print("\n=== List Comprehension Alternative ===")
# Often clearer than map/filter!
positives_comp = [x for x in numbers if x > 0]
print(f"Positives (comprehension): {positives_comp}")
squared_comp = [x ** 2 for x in numbers]
print(f"Squared (comprehension): {squared_comp}")
combined_comp = [x ** 2 for x in numbers if x > 0]
print(f"Squares of positives (comprehension): {combined_comp}")
if __name__ == "__main__":
main()
filter(lambda x: x > 0, nums) keeps positives. map(lambda x: x*2, nums) doubles.
Multiple arguments in lambda
Lambdas can take multiple (or zero) arguments.
def main():
print("=== Lambda with Multiple Arguments ===\n")
# Two arguments
add = lambda x, y: x + y
multiply = lambda x, y: x * y
print(f"add(5, 3) = {add(5, 3)}")
print(f"multiply(5, 3) = {multiply(5, 3)}")
# Three or more
volume = lambda l, w, h: l * w * h
print(f"volume(2, 3, 4) = {volume(2, 3, 4)}")
print("\n=== Lambda with No Arguments ===")
get_pi = lambda: 3.14159
greet = lambda: "Hello, World!"
print(f"get_pi() = {get_pi()}")
print(f"greet() = {greet()}")
print("\n=== Lambda with Default Arguments ===")
power = lambda x, n=2: x ** n
print(f"power(5) = {power(5)}") # 5^2 = 25
print(f"power(5, 3) = {power(5, 3)}") # 5^3 = 125
greet_person = lambda name, greeting="Hello": f"{greeting}, {name}!"
print(greet_person("Alice"))
print(greet_person("Bob", "Hi"))
print("\n=== Practical: reduce() ===")
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# Sum using reduce
total = reduce(lambda acc, x: acc + x, numbers)
print(f"Sum of {numbers} = {total}")
# Product using reduce
product = reduce(lambda acc, x: acc * x, numbers)
print(f"Product of {numbers} = {product}")
# Max using reduce
maximum = reduce(lambda a, b: a if a > b else b, numbers)
print(f"Max of {numbers} = {maximum}")
if __name__ == "__main__":
main()
lambda a, b: a + b takes two args. lambda: 42 takes none.
Common lambda patterns
Frequently used lambda idioms.
def main():
print("=== Common Lambda Patterns ===\n")
# Pattern 1: Getter/accessor
print("=== Getter Pattern ===")
users = [
{"name": "Alice", "score": 85},
{"name": "Bob", "score": 92},
{"name": "Charlie", "score": 78}
]
names = list(map(lambda u: u["name"], users))
print(f"Names: {names}")
top_scorer = max(users, key=lambda u: u["score"])
print(f"Top scorer: {top_scorer['name']}")
# Pattern 2: Conditional expression
print("\n=== Conditional Pattern ===")
numbers = [-3, -1, 0, 2, 5]
# Ternary in lambda
signs = list(map(lambda x: "pos" if x > 0 else ("neg" if x < 0 else "zero"),
numbers))
print(f"Numbers: {numbers}")
print(f"Signs: {signs}")
# Pattern 3: Method call
print("\n=== Method Call Pattern ===")
words = ["Hello", "WORLD", "Python"]
lowered = list(map(lambda s: s.lower(), words))
print(f"Lowered: {lowered}")
# Pattern 4: Tuple operations
print("\n=== Tuple Pattern ===")
pairs = [(1, "b"), (3, "a"), (2, "c")]
# Sort by second element
by_second = sorted(pairs, key=lambda p: p[1])
print(f"By second element: {by_second}")
# Pattern 5: Composition
print("\n=== Composition Pattern ===")
# Chain operations
process = lambda x: x.strip().lower().replace(" ", "_")
titles = [" Hello World ", " Python CODE ", " DATA Science "]
slugs = list(map(process, titles))
print(f"Slugs: {slugs}")
if __name__ == "__main__":
main()
Key extraction, default values, and simple transformations are common uses.
Exercise: limitations.py
Explore when NOT to use lambda - prefer def for complex logic