Audience: Grade 8–9 students with intermediate Python skills
Goal: Write less code while doing more, by mastering small anonymous functions (lambdas) and powerful one-liners for building lists (comprehensions).
Why this matters
- You'll clean, reshape, and sort data in a few lines.
- You'll write code that's both faster and easier to read—when used wisely.
- These tools show up everywhere: data science, web backends, and coding interviews.
Part 1 — Lambda Functions
What is a lambda?
- A lambda is a tiny, anonymous function defined in one expression.
- Syntax:
lambda arguments: expression - It has no name (unless you assign it to a variable), and it must contain exactly one expression (no multi-line statements).
Examples
1) Basic math
square = lambda x: x * x
print(square(5)) # 25
add = lambda a, b: a + b
print(add(2, 3)) # 52) Sorting with a key function
names = ["alice", "Bob", "carol", "dave"]
print(sorted(names, key=lambda s: s.lower()))
# Case-insensitive sort
full_names = ["Ada Lovelace", "Alan Turing", "Grace Hopper"]
print(sorted(full_names, key=lambda n: n.split()[-1]))
# Sort by last name3) Sorting by multiple criteria
students = [
{"name": "Ava", "score": 91},
{"name": "Ben", "score": 91},
{"name": "Cara", "score": 88},
]
# Highest score first, then name A→Z
print(sorted(students, key=lambda s: (-s["score"], s["name"])))4) Pair with map/filter
nums = [1, 2, 3, 4, 5]
print(list(map(lambda x: x * 2, nums))) # [2, 4, 6, 8, 10]
print(list(filter(lambda x: x % 2 == 0, nums))) # [2, 4]Tip: Often, list comprehensions are clearer than map/filter with lambda. See Part 2.
Limitations and tips
- One expression only. No assignments, loops, or multiple statements inside.
- Use lambdas for short, throwaway functions (like keys for sorted).
- For anything complex or reused, define a normal
deffunction with a name and docstring for readability.
Advanced: closures and the "late binding" gotcha
Lambdas remember variables from outer scopes. But be careful inside loops:
funcs = []
for i in range(3):
funcs.append(lambda: i) # Captures the same 'i'
print([f() for f in funcs]) # [2, 2, 2] (surprise!)
# Fix by freezing the current value using a default argument:
funcs = []
for i in range(3):
funcs.append(lambda i=i: i)
print([f() for f in funcs]) # [0, 1, 2]Part 2 — List Comprehensions
What is a list comprehension?
- A fast way to build lists using a single readable expression.
- Syntax:
[expression for item in iterable if condition] - Reads like: "Make a list of expression for each item, but only if condition."
Basic examples
1) Transform items
nums = [1, 2, 3, 4]
squares = [n*n for n in nums]
print(squares) # [1, 4, 9, 16]2) Filter items
evens = [n for n in nums if n % 2 == 0]
print(evens) # [2, 4]3) Conditional expression (if/else) inside the expression
labels = ["even" if n % 2 == 0 else "odd" for n in nums]
print(labels) # ['odd', 'even', 'odd', 'even']4) Nested loops (flatten a 2D list)
grid = [[1, 2], [3, 4], [5]]
flat = [x for row in grid for x in row]
print(flat) # [1, 2, 3, 4, 5]Map/filter equivalents
Map with lambda:
list(map(lambda n: n*n, nums))Same with comprehension (usually clearer):
[n*n for n in nums]Filter with lambda:
list(filter(lambda n: n % 2 == 0, nums))Same with comprehension:
[n for n in nums if n % 2 == 0]More comprehensions
Set comprehension (unique results)
names = ["ann", "bob", "ann", "cara"]
unique_lengths = {len(n) for n in names}
print(unique_lengths) # {3, 4}Dict comprehension
scores = {"ann": 81, "bob": 95, "cara": 88}
grade = {name: ("A" if s >= 90 else "B" if s >= 80 else "C") for name, s in scores.items()}
print(grade) # {'ann': 'B', 'bob': 'A', 'cara': 'B'}Generator expression (like list comprehension, but lazy)
big = (n*n for n in range(10_000_000)) # uses little memory
print(next(big), next(big), next(big)) # 0 1 4Performance and readability
- List comprehensions are often faster than building lists with append in a loop.
- Rule of thumb: if it fits comfortably on one line and is easy to read, use a comprehension. Otherwise, use a normal loop for clarity.
- In Python 3, the variable used inside a comprehension does not leak into the outer scope.
When to use what
- Use lambda mostly as a short key function (
sorted,min,max) or with small map/filter tasks. - Prefer list comprehensions to map/filter for clarity—unless a named function already exists (e.g.,
map(str, items)).
Hands-on Practice Snippets
1) Case-insensitive unique words, sorted by length then alphabetically
text = "Python makes powerful patterns possible"
words = {w.lower() for w in text.split()} # unique, lowercased
result = sorted(words, key=lambda w: (len(w), w))
print(result)2) Top 3 longest lines from a file (pretend we have lines)
lines = ["short", "a bit longer", "the longest line here", "mid"]
top3 = sorted(lines, key=lambda s: len(s), reverse=True)[:3]
print(top3)3) Flatten, then filter
matrix = [[1, 2, 3], [4, 5], [6, 7, 8]]
even_flat = [x for row in matrix for x in row if x % 2 == 0]
print(even_flat) # [2, 4, 6, 8]Mini Project — Student Scoreboard Cleaner and Analyzer
You'll clean messy student data, compute grades, and produce a sorted leaderboard using lambdas and comprehensions.
Starter data
raw = [
" alice , 88 ",
"Bob,95",
"cara, 105", # over 100, should clamp to 100
"Dan,-3", # negative, should clamp to 0
" , 70", # missing name -> drop
"Eve, ninety", # non-numeric -> drop
"frank, 72"
]Tasks
- Parse each line into (name, score).
- Strip spaces, title-case the name.
- Convert score to int; if it fails, drop the record.
- Clamp scores to the range [0, 100].
- Curve scores by +5 but not above 100.
- Assign letter grades: A (≥90), B (80–89), C (70–79), D (60–69), F (<60).
- Sort by score (desc), then name (asc), using a lambda key.
- Print the top 3 and a summary (count, average score).
Hint plan
- Use a comprehension to parse and filter invalid lines.
- Use min/max or clamp with:
max(0, min(100, score)) - Use a dict/list comprehension to build final structures.
Solution walkthrough
Step 1–2: Parse and clean
def try_parse_record(line):
if "," not in line:
return None
name_part, score_part = line.split(",", 1)
name = name_part.strip().title()
score_str = score_part.strip()
if not name:
return None
try:
score = int(score_str)
except ValueError:
return None
# clamp to [0, 100]
score = max(0, min(100, score))
return {"name": name, "score": score}
cleaned = [rec for rec in (try_parse_record(line) for line in raw) if rec is not None]
print(cleaned)Step 3: Curve scores (use a comprehension)
curved = [{**rec, "score": min(100, rec["score"] + 5)} for rec in cleaned]Step 4: Letter grades
def letter(score):
return (
"A" if score >= 90 else
"B" if score >= 80 else
"C" if score >= 70 else
"D" if score >= 60 else
"F"
)
graded = [{**rec, "grade": letter(rec["score"])} for rec in curved]Step 5: Sort using a lambda key
leaderboard = sorted(graded, key=lambda r: (-r["score"], r["name"]))
for row in leaderboard:
print(row)Step 6: Top 3 and summary
top3 = leaderboard[:3]
print("Top 3:")
for r in top3:
print(f'{r["name"]}: {r["score"]} ({r["grade"]})')
avg = sum(r["score"] for r in leaderboard) / len(leaderboard)
print(f"Total students: {len(leaderboard)}")
print(f"Average score: {avg:.1f}")Expected output idea (will vary by data)
- Names cleaned (Alice, Bob, Cara, Dan, Frank)
- Scores clamped and curved
- Sorted by score desc, then name
- Average printed
Extension challenges
- Add pass/fail rate using a comprehension.
- Group by grade letter into a dict:
{grade: [names...]}via dict comprehension. - Export to CSV string lines like "Name,Score,Grade" using a list comprehension.
Common Pitfalls and Pro Tips
- Don't overuse lambdas. If it gets long or you need comments, use
def. - For big pipelines, prefer comprehensions or generator expressions over building large temporary lists.
- Remember: in Python 3, comprehension variables don't leak to outer scope.
- For complex sorts, use a lambda that returns a tuple:
key=lambda x: (primary, secondary, ...). - If you hit the late-binding trap in lambdas inside loops, freeze variables with defaults:
lambda v=v: v.
Summary
- Lambda functions are tiny, anonymous functions perfect for short tasks like sort keys or simple transforms.
- List comprehensions build lists quickly and readably; they can transform, filter, and even nest loops in one expression.
- Prefer list comprehensions over map/filter for readability, unless using an existing function like
strorint. - Combined, these tools help you clean data, sort smartly, and compute results in fewer lines—skills used in real-world Python every day.
Practice prompt
Given a list of movie dicts with "title", "year", "rating", build:
- A list of titles for movies after 2015 with rating ≥ 8.0, sorted by rating desc.
- A dict mapping title → "Classic" if year < 2000 else "Modern".
Use one lambda for sorting and comprehensions for the rest.