061. Dictionary Keys And Values
Separate keys from values for flexible iteration
061. Dictionary Keys And Values
Aryan’s monitor stores per-process metrics in a dict:
stats = {
"Chrome": {"rss_mb": 512, "cpu_pct": 8.2},
"Slack": {"rss_mb": 210, "cpu_pct": 1.1},
"PyCharm": {"rss_mb": 890, "cpu_pct": 22.4},
}He needs to iterate in different ways depending on the task:
# Keys only — print all process names
for name in stats: # same as stats.keys()
print(name)
# Values only — total memory across all processes
total_mb = sum(v["rss_mb"] for v in stats.values())
print(f"Total tracked: {total_mb:.0f} MB")
# Key-value pairs — full report
for name, metrics in stats.items():
print(f"{name:20s} {metrics['rss_mb']:6.0f} MB {metrics['cpu_pct']:.1f}%")
# Find highest-memory process without a manual loop
worst = max(stats, key=lambda name: stats[name]["rss_mb"])
print(f"Worst: {worst}")The classic mistake: sum(stats) tries to sum the string keys — TypeError. The fix: sum(stats.values()) or sum(v["rss_mb"] for v in stats.values()).
💡 Fun fact: Dict views (.keys(), .values(), .items()) are dynamic — they reflect changes to the dict in real time. This is why they’re called “views” rather than snapshots. In Python 2, .keys() and .values() returned static lists; Python 3 changed them to lazy views to save memory and improve performance, especially when you’re iterating over large dicts without needing all keys/values at once.
⚠️ Watch out: Modifying a dict while iterating over it with .items() raises RuntimeError: dictionary changed size during iteration. This surprises beginners who try to delete keys inside a for k, v in d.items(): loop. The safe pattern is to collect keys to delete first: to_delete = [k for k, v in d.items() if condition]; for k in to_delete: del d[k].
🤔 Think about it: max(stats, key=lambda name: stats[name]["rss_mb"]) finds the process with highest memory by iterating keys and looking up values. max(stats.items(), key=lambda kv: kv[1]["rss_mb"]) iterates key-value pairs directly. Both work — which approach is cleaner, and does the performance differ when the dict has thousands of entries?
Learning objectives
- Iterate key-value pairs with .items()
- Use .values() to access only values
- Apply sum() and max() with dict views
Key concepts
- dict.items()
- dict.keys()
- dict.values()
- iteration
Try it
Concept detail
Dict views: d.keys() (all keys), d.values() (all values), d.items() (key-value tuples).
Iteration patterns: for k in d: — keys only (same as for k in d.keys()) for v in d.values(): — values only for k, v in d.items(): — key-value pairs unpacked
Useful built-ins on dict views: sum(d.values()) — sum all values max(d, key=d.get) — key with maximum value sorted(d.keys()) — sorted list of keys list(d.values()) — snapshot of values as a list
Views are dynamic: they reflect the current dict contents immediately. Modifying d while iterating over d.items() raises RuntimeError — iterate a copy if needed.
Solution
def top_scorer(scores):
best_name = None
best_score = -1
for name, score in scores.items():
if score > best_score:
best_score = score
best_name = name
return best_name
def passing_students(grades):
result = []
for name, grade in grades.items():
if grade >= 60:
result.append(name)
return sorted(result)
def total_score(scores):
return sum(scores.values())
def invert_dict(d):
return {v: k for k, v in d.items()}Tests
SCORES = {"Alice": 95, "Bob": 72, "Charlie": 88}
GRADES = {"Alice": 90, "Bob": 55, "Charlie": 70}
def test_top_scorer():
assert top_scorer(SCORES) == "Alice"
def test_top_scorer_single():
assert top_scorer({"Only": 42}) == "Only"
def test_passing_students():
result = passing_students(GRADES)
assert result == ["Alice", "Charlie"]
def test_passing_students_none():
assert passing_students({"Alice": 50, "Bob": 45}) == []
def test_total_score():
assert total_score(SCORES) == 255
def test_invert_dict():
d = {"a": 1, "b": 2}
inv = invert_dict(d)
assert inv == {1: "a", 2: "b"}