← Home

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"}

Resources