Skip to content
VLSI Mentor

Python Part I · Module 8 · Dictionaries

Looping Over keys, values and items

A results table is only useful if you can go through it. You might want every test name, or every outcome, or — most often — both halves together so you can print a line per result. Python offers all three, and the choice between them is genuinely a choice about the question you are asking rather than a style preference. This chapter also clears up something that trips people up the first time they look closely: the three methods do not hand you lists, and what they do hand you behaves in a way that is worth understanding before you are surprised by it.

Foundation14 min readPythonPart IFundamentalsDictionariesIteration

Part I · Module 8 · Chapter 8.5 · Looping Over keys, values and items

1. A Plain Loop Gives You the Keys

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
for name in results:
    print(name)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
reset
crc

The loop syntax is Chapter 5.4's, unchanged — one pass per entry, the loop variable referring to one thing at a time.

What it refers to is the key. Not the value, and not a pair. That is worth noticing because it is a choice Python made, and it follows from Chapter 8.1's model: a dictionary is organised by key, so the keys are what it naturally hands out.

The proof that plain iteration yields keys is what happens if you assume otherwise:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
d = {"a": 1}
for k, v in d:
    print(k, v)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ValueError: not enough values to unpack (expected 2, got 1)

That is Chapter 6.5's unpacking error. The loop handed over the key "a" — a one-character string — and the header asked for two values out of it. There was only one character, so the unpacking failed. Had the loop been giving pairs, this would have worked; it is not.

2. keys(): Which Subjects Are Present?

The explicit form says the same thing in words:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
for name in results.keys():
    print(name)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
reset
crc

Identical output. for name in results: and for name in results.keys(): do the same thing, and the second is worth writing when the surrounding code also uses .values() or .items() — the symmetry makes the intent obvious at a glance.

The question it answers is which test names do I have a result for?

3. values(): Which Outcomes Are Present?

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
for status in results.values():
    print(status)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
PASS
FAIL
PASS

Three outcomes, with "PASS" appearing twice — Chapter 8.2's point that values need not be unique, visible here.

The question is what outcomes occurred? Note that it has lost track of which test produced which. If you need that, you want the next section.

4. items(): Which Goes With Which?

This is the one you will use most:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
for name, status in results.items():
    print(name, status)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke PASS
reset FAIL
crc PASS

One line per result, with both halves available in the body. That is the summary the canonical curriculum names for this chapter.

Two names in the loop header is new, and it is not special dictionary syntax. Each thing items() hands over is a tuple:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL"}
for pair in results.items():
    print(pair, type(pair))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
('smoke', 'PASS') <class 'tuple'>
('reset', 'FAIL') <class 'tuple'>

A (key, value) tuple per entry. So for name, status in results.items(): is Chapter 6.5's tuple unpacking, applied once per pass: the loop produces a two-element tuple, and the two names on the left take its two parts by position.

Compare the alternative, which uses only Chapter 8.1:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL"}
for name in results:
    print(name, results[name])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke PASS
reset FAIL

That works and does a lookup on every pass to recover something items() would have handed you. For a short loop the difference is cosmetic; items() is the clearer statement of intent.

5. What These Methods Actually Return

Here is the detail that surprises people. .keys() does not return a list:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL"}
print(results.keys())
print(results.values())
print(results.items())
print(type(results.keys()))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
dict_keys(['smoke', 'reset'])
dict_values(['PASS', 'FAIL'])
dict_items([('smoke', 'PASS'), ('reset', 'FAIL')])
<class 'dict_keys'>

The type is dict_keys, and it displays as dict_keys([...]) rather than as a bare list. These are called view objects: they provide access to the dictionary's keys, values or pairs without being separate collections.

They support what you would expect:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
print(len(results.keys()), len(results.values()), len(results.items()))
print("smoke" in results.keys())
print("PASS" in results.values())
print(("smoke", "PASS") in results.items())
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3 3 3
True
True
True

Length, membership and iteration all work. What they are not is lists, so they have no [0] and no .append().

A view is live

This is the property that makes "view" the right word:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
ks = results.keys()
print(len(ks))
results["new"] = "PASS"
print(len(ks))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3
4

ks was not rebuilt and nothing was reassigned — yet its length changed, because it is a window onto the dictionary rather than a snapshot of it. Add an entry and the view shows it.

6. The Order You Get

Iteration follows insertion order, the property Chapter 8.1 established:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
d = {}
d["b"] = 1
d["a"] = 2
print(list(d))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
['b', 'a']

b first, because it was added first. That is dependable — genuinely unlike a set, where Chapter 7.2 measured five different orders across twelve runs.

Insertion order is not alphabetical order. When you want names sorted, ask for it:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
print(sorted(results))
print(sorted(results.keys()))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
['crc', 'reset', 'smoke']
['crc', 'reset', 'smoke']

sorted() on a dictionary sorts its keys and returns a list — which also means for name in sorted(results): walks the table alphabetically, the natural way to produce a report that reads the same whatever order the results arrived in.

And recall Chapter 8.4's finding: replacing an existing key's value does not move it. A key keeps the position it had when it was first inserted, so re-assigning a result does not reshuffle your report.

7. Choosing Between Them

Now that each has arrived with a question attached:

The question you are askingUse
Which subjects do I have entries for?for k in d: or d.keys()
What outcomes occurred, regardless of which test?d.values()
Which subject goes with which outcome?d.items()

items() is the common case for reporting. values() is for questions about outcomes alone — counting how many passed, say. keys() is for questions about the subjects.

8. Counting, Without a Counter

A small example of the body doing real work, using only what you have:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = {"smoke": "PASS", "reset": "FAIL", "crc": "PASS"}
total = 0
for status in results.values():
    total += 1
print(total)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3

That counts every outcome — which len(results) would have told you more directly. Counting only some of them, such as just the failures, needs a way to decide per entry, and deciding is the if statement in Module 9. Module 10 then covers counting patterns properly.

What this chapter establishes is the walk itself: one pass per entry, both halves available, in a known order.

9. Do Not Change the Dictionary While Looping

The rule from Chapters 5.4 and 7.2, and Python enforces it here:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
d = {"a": 1, "b": 2}
for k in d:
    d["c"] = 3
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
RuntimeError: dictionary changed size during iteration

Deleting is the same:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
d = {"a": 1, "b": 2}
for k in d:
    del d[k]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
RuntimeError: dictionary changed size during iteration

10. Predict, Run, Observe

Predict every line before reading on.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
d = {"b": 2, "a": 1, "c": 3}
for k in d:
    print(k)
print(list(d.values()))
print(sorted(d))
print(len(d.items()))
print(("a", 1) in d.items())
print(type(d.keys()))

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
b
a
c
[2, 1, 3]
['a', 'b', 'c']
3
True
<class 'dict_keys'>

The loop prints b, a, c — insertion order, which here is the order written in the literal, not alphabetical.

list(d.values()) is [2, 1, 3], matching that same order.

sorted(d) is alphabetical and returns a list of keys.

("a", 1) in d.items() is True — that exact pair is an entry. Note that ("a", 2) would be False: items membership checks the pair, not just the key.

And type(d.keys()) is dict_keys, not list.

11. Exercises

Exercise 1 — three walks. For widths = {"clk": 1, "addr": 32, "data": 64}, write the loop that prints every signal name, the loop that prints every width, and the loop that prints name width on one line each.

Exercise 2 — predict. For d = {"x": 10, "y": 20}, give each result and verify: (a) list(d) (b) list(d.values()) (c) list(d.items()) (d) len(d.items()) (e) "x" in d.keys() (f) 10 in d.values() (g) ("x", 10) in d.items()

Exercise 3 — which view. For each question, name the right method and write the loop header: (a) how many distinct outcomes occurred (b) print a line per test with its result (c) list the tests that have results at all (d) check whether any test produced "FAIL"

Exercise 4 — the unpacking error. Run for k, v in {"ab": 1}: and write down the exact message. Explain in three sentences what the loop actually handed over, why two names could not take it, and what happens if you try the same with a key of length two.

Exercise 5 — views are not lists. Predict what each does, verify, and explain the two that fail: (a) d.keys()[0] (b) list(d.keys())[0] (c) d.keys().append("z") (d) len(d.keys())

Exercise 6 — the live view. Predict both numbers, verify, and explain in two sentences:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
d = {"a": 1}
v = d.values()
print(len(v))
d["b"] = 2
print(len(v))

Exercise 7 — order. Build a dictionary by adding three keys in non-alphabetical order, then print list(d) and sorted(d). Say in one sentence what determines each, and which one you would use for a report.

Exercise 8 — the iteration rule. Explain in two sentences why for k in d: del d[k] raises, name the exact error, and say what you would do instead.

12. Summary

  • A plain for over a dictionary gives the keys — not values, not pairs. for k, v in d: fails with an unpacking error, which is the proof.
  • .keys() asks which subjects are present, .values() which outcomes occurred, .items() which goes with which.
  • items() is the common case for a per-entry summary.
  • Each item is a (key, value) tuple, so for name, status in d.items(): is Chapter 6.5's unpacking — not special syntax.
  • These methods return views, not lists. type(d.keys()) is dict_keys; views are not indexable and have no append.
  • A view is live — adding an entry changes its length without reassigning anything.
  • Use list(...) when you genuinely need a list, such as to keep a snapshot or to index it.
  • Iteration follows insertion order, dependably — and replacing a value does not move its key.
  • sorted(d) sorts the keys and returns a list, which is how you produce a report in a stable, readable order.
  • Do not add or remove entries while looping — RuntimeError: dictionary changed size during iteration. Changing an existing key's value is fine.

You can read, change and walk a dictionary. The next chapter is about what happens when two names refer to one.

Where this fits

Part of the Python curriculum.