Skip to content
VLSI Mentor

Python Part I · Module 10 · Loops

Looping Over Strings, Lists, Tuples, Sets and Dictionaries

Modules 4 to 8 built five collections, each with its own purpose and its own access rules. A list finds things by position, a dictionary by key, a set answers only whether something is present. It would be reasonable to expect five ways of looping over them. There is one. The same for statement walks every collection in the language, which is a real piece of design rather than a convenience — it means the loop you learned in Chapter 10.1 is the last loop you need to learn. What differs is only what a single pass hands you, and for two of the five that answer catches people out: one gives you something other than what you asked for, and one gives it in an order you cannot depend on.

Foundation16 min readPythonPart IFundamentalsLoopsCollections

Part I · Module 10 · Chapter 10.3 · Looping Over Strings, Lists, Tuples, Sets and Dictionaries

1. The Same Statement, Five Times

Nothing below is new syntax. It is the one loop from Chapter 10.1, pointed at five different things:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
for ch in "axi":
    print(ch)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a
x
i
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
for item in ["smoke", "reset"]:
    print(item)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
reset
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
for field in ("axi_smoke", 4210):
    print(field)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi_smoke
4210

Three collections, three loops that differ in nothing but the thing after in. The remaining two — sets and dictionaries — work identically and need a paragraph each about what they hand you.

2. A String Hands You Characters

Chapter 4.4 established that a string is a sequence, so looping it gives one character per pass:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
signal = "clk_i"

for ch in signal:
    print(ch)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
c
l
k
_
i

Each item is itself a string of length one — Python has no separate character type:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
for ch in "ax":
    print(ch, type(ch), len(ch))
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a <class 'str'> 1
x <class 'str'> 1

That means every string method is available on each character, which makes per-character checks read plainly:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
name = "data_q2"
digits = 0

for ch in name:
    if ch.isdigit():
        digits = digits + 1

print("digits in the name:", digits)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
digits in the name: 1

3. A List Hands You Items

The straightforward case, and the one everything else is compared against:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
widths = [1, 8, 32]

for width in widths:
    print(width, "bits")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1 bits
8 bits
32 bits

An item can be anything, including another collection — Section 9 returns to that.

4. A Tuple Hands You Items, in Order

A tuple iterates exactly like a list, and its fixed order is guaranteed:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
record = ("axi_smoke", 4210, "PASS")

for field in record:
    print(field)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi_smoke
4210
PASS

Looping over the fields of one record is usually not what you want, though, because the fields mean different things. The common and useful case is a list of tuples, where each pass hands you one whole record — and Chapter 6.5's unpacking can take it apart in the for line itself:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [("axi_smoke", 4210, "PASS"), ("axi_burst", 4211, "FAIL")]

for test, seed, status in results:
    print(test, "at seed", seed, "->", status)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
axi_smoke at seed 4210 -> PASS
axi_burst at seed 4211 -> FAIL

Three names on the left of in, one tuple per pass, unpacked automatically. This is the same unpacking as a, b = (1, 2); the loop simply does it on every pass.

5. A Set Hands You Members, in No Dependable Order

A set iterates like everything else:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
failed = {"reset", "crc", "burst"}

for name in sorted(failed):
    print(name)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
burst
crc
reset

Note the sorted(). It is there because the order a set hands you its members is not dependable, and that is not a theoretical caution. Running a loop that collects the members of {"reset", "crc", "burst"} in twelve fresh interpreters produced all six possible orders — three runs gave one order, three gave another, and the remaining four orders appeared twice, twice, once and once.

Chapter 7.2 established why: a set's layout depends on hash values, and Python randomises string hashing per process. The consequence for a loop is concrete — a report generated by iterating a set directly will list its entries differently on different runs, and a test that compares two such reports will fail intermittently for no reason connected to the design.

When order genuinely does not matter — counting, or checking membership — iterate the set directly and nothing is lost:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
failed = {"reset", "crc", "burst"}
long_names = 0

for name in failed:
    if len(name) > 3:
        long_names = long_names + 1

print("failures with names longer than three characters:", long_names)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
failures with names longer than three characters: 2

The count is the same whatever order the loop visited them in, so this is safe. The rule is simple: if the output depends on the order, sort first.

6. A Dictionary Hands You Keys

This is the one that catches everyone:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = {"smoke": "PASS", "reset": "FAIL"}

for key in status:
    print(key)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
reset

Keys, not values, and not pairs. The loop variable's name has no influence on this whatsoever:

Azvya Education Pvt. Ltd.VLSI Mentor
BROKEN ON PURPOSE
status = {"smoke": "PASS", "reset": "FAIL"}

for value in status:
    print(value)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke
reset

Calling it value printed the keys anyway. Nothing raised, nothing warned, and a program that goes on to compare value against "PASS" will simply never match.

The order is dependable here — dictionaries preserve insertion order, as Chapter 8.1 established — so unlike a set, iterating a dictionary directly gives a repeatable result.

To reach the value, look it up:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = {"smoke": "PASS", "reset": "FAIL"}

for test in status:
    print(test, "->", status[test])
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
smoke -> PASS
reset -> FAIL

That is correct and it does a lookup per pass to reach something the loop could have handed you directly. Section 7 is the better form.

7. .items(), .keys() and .values()

Chapter 8.5 introduced the three views. In a for line they are at their most useful:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status = {"smoke": "PASS", "reset": "FAIL"}

print("--- keys ---")
for test in status.keys():
    print(test)

print("--- values ---")
for result in status.values():
    print(result)

print("--- items ---")
for test, result in status.items():
    print(test, "->", result)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
--- keys ---
smoke
reset
--- values ---
PASS
FAIL
--- items ---
smoke -> PASS
reset -> FAIL

.items() hands you a two-field tuple per pass, and the two names before in unpack it — Section 4's mechanism, applied to the most common case in the language.

8. What Each Collection Hands You

CollectionOne pass gives youOrderNotes
strone character, as a str of length 1left to right, guaranteedsplit first if you want words
listone itempositional, guaranteedthe straightforward case
tupleone fieldpositional, guaranteedunpack a list of tuples in the for line
setone membernot dependablesort if the output depends on order
dictone keyinsertion order, guaranteeduse .items() for key and value
dict.values()one valuematches key orderno way back to the key
dict.items()a (key, value) tupleinsertion orderunpack it with two names
rangeone integerascending or descending by stepChapter 10.4

9. Looping Over a Nested Structure

Chapter 8.7 built results that are a list of dictionaries. Looping over it hands you one dictionary per pass, and everything you know about dictionaries then applies:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
results = [
    {"test": "axi_smoke", "seed": 4210, "status": "PASS"},
    {"test": "axi_burst", "seed": 4211, "status": "FAIL"},
    {"test": "reset_seq", "seed": 4212, "status": "FAIL"},
]

failed = []

for result in results:
    if result["status"] == "FAIL":
        failed.append(result["test"])

print("failed:", failed)
print(len(failed), "of", len(results), "failed")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
failed: ['axi_burst', 'reset_seq']
2 of 3 failed

One loop, not two. The loop walks the outer list; reaching inside each item is a lookup, not another loop. Needing a loop inside a loop is a different situation and Chapter 10.11 covers it.

10. Predict, Run, Observe

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# A
for ch in "ok":
    print(ch)

# B
pairs = [(1, "a"), (2, "b")]
for number, letter in pairs:
    print(number, letter)

# C
d = {"x": 10, "y": 20}
total = 0
for thing in d:
    total = total + len(thing)
print("total:", total)

# D
d = {"x": 10, "y": 20}
total = 0
for thing in d.values():
    total = total + thing
print("total:", total)

The verified output:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
o
k
1 a
2 b
total: 2
total: 30

A — two characters.

B — each item is a two-field tuple, unpacked by the two names.

C — total: 2. The loop walked the keys, which are the one-character strings "x" and "y", so len(thing) was 1 each time. Nothing about this raises.

D — total: 30. .values() is what C should have said.

C and D differ by seven characters and give answers that are not even the same kind of thing. That is the whole reason this chapter exists.

11. Exercises

Exercise 1 — five loops. Write one loop for each of "hi", [1, 2], (3, 4), {"a", "b"} and {"k": "v"} that prints each item. For the set, make the output dependable. Say in one sentence what the dictionary loop printed.

Exercise 2 — count the digits. Given names = ["data_q2", "clk", "addr_r15"], count how many digits appear across all names. You will need a loop over the list and a loop over each name — write it with the inner one as a per-character check, and say which of the two is doing the per-character work.

Exercise 3 — the wrong name. Write for value in {"a": 1}: and print the loop variable. Explain in two sentences why it printed what it did and why no error appeared.

Exercise 4 — unpack in the for line. Given results = [("smoke", "PASS"), ("reset", "FAIL")], print smoke: PASS and reset: FAIL using unpacking in the for statement rather than indexing.

Exercise 5 — order dependence. For each, say whether the result depends on set iteration order: (a) counting the members (b) printing them one per line (c) checking whether "crc" is among them (d) building a comma-joined string of them. Fix the ones that depend on it.

Exercise 6 — three views. For widths = {"clk": 1, "data": 32, "addr": 16}, print the names only, the widths only, and the pairs — using the right view for each. Then print the total of all widths.

Exercise 7 — list of dictionaries. Using Section 9's results, build a list of the seeds of the failing tests, and print the test name of the first failure. State how many loops you needed.

Exercise 8 — predict the type. For each loop, say what type(item) would print on the first pass: (a) for item in "ab" (b) for item in [(1, 2)] (c) for item in {"a": 1} (d) for item in {"a": 1}.items(). Verify all four.

12. Summary

  • One for statement walks every collection in the language. Only what a pass hands you differs.
  • A string hands you one character at a time, each a str of length 1 — split first if you want words.
  • A list and a tuple hand you items in guaranteed order.
  • A list of tuples can be unpacked in the for line with one name per field.
  • A set hands you members in no dependable order — twelve runs over a three-string set produced all six possible orders. Sort when the output depends on order; iterate directly when it does not.
  • A set of small integers iterating in order is an artifact, not a promise.
  • A dictionary hands you keys. Naming the loop variable value changes nothing and raises nothing.
  • Dictionary order is dependable (insertion order), unlike a set's.
  • Use .items() when you need the key and the value, .values() when you need only values, and plain for key in d: when you need only keys.
  • Looping a nested structure hands you one whole inner object per pass; reaching inside it is a lookup, not another loop.

The next chapter takes the one collection in the table that has not been explained yet, and settles why range(10) stops at 9.

Where this fits

Part of the Python curriculum.