Python Part I · Module 6 · Tuples
Tuples as Fixed Records and Keys
Module 5 gave you a collection that grows, shrinks and reorders. A great deal of real data is not like that. A coordinate has exactly two numbers and always will. A test result is a name and an outcome — two things, in that order, and the day it becomes three things it is a different kind of record entirely. Python has a second ordered collection for exactly this case, and the point of it is not that you are forbidden from changing it. The point is that its shape is part of what it means. This chapter introduces the tuple, corrects the single most common misunderstanding about how one is written, and shows the capability that immutability unlocks.
Foundation13 min readPythonPart IFundamentalsTuplesCollections
Part I · Module 6 · Chapter 6.1 · Tuples as Fixed Records and Keys
1. Some Collections Are Not Meant to Grow
A list is the right tool when the collection itself is in motion. The suite of tests to run grows as you add tests; the failures found grow as the run proceeds. Chapter 5.3 was entirely about that.
Now consider a different kind of data. A job in a regression queue is a test name and a seed:
job = ("axi_burst", 48210)
print(job)('axi_burst', 48210)That is a tuple: an ordered collection, written with commas, whose contents cannot be changed after it is created.
But read what it actually represents, because this is the part that matters. job is not "a collection of two things that happens to have two things in it right now". It is a record with two fixed positions: position 0 is the test, position 1 is the seed. Appending a third element would not make it a longer job — it would make it something that is no longer a job at all.
It behaves as you would expect from a collection, and none of this needs re-teaching:
job = ("axi_burst", 48210)
print(type(job))
print(len(job))<class 'tuple'>
2Type tuple, length 2. len() counts elements exactly as it did for lists and strings.
2. It Is the Comma That Makes a Tuple
Here is the rule almost every tutorial gets wrong, and getting it right now is what makes Chapter 6.2 make sense.
People say "parentheses create a tuple." They do not. The comma does.
point = 10, 20
print(point)
print(type(point))(10, 20)
<class 'tuple'>No parentheses anywhere on that line, and the result is a tuple. Python printed it with parentheses — that is how a tuple is displayed — but they were not needed to create it.
So what are the parentheses for in ("axi_burst", 48210)? The same thing they are for everywhere else in Python: grouping. They mark where the tuple begins and ends, which matters when a tuple sits inside something larger or when a line would otherwise be ambiguous. They are usually good practice, and they are not the mechanism.
There is exactly one case where the parentheses genuinely do the work, and it is the empty tuple — because there is nothing for a comma to separate:
empty = ()
print(empty, type(empty), len(empty))() <class 'tuple'> 0Zero elements, type tuple. An empty tuple is rare in practice, for the good reason that a record with no parts is not usually a useful thing to have.
3. A Tuple Holds Anything, in Order
Everything Chapter 5.1 said about lists holding any values applies here, and for records it is more often useful to mix types, because the parts of a record genuinely are different kinds of thing:
result = ("smoke_test", "PASS", 12.4)
print(result)
print(type(result[0]), type(result[1]), type(result[2]))('smoke_test', 'PASS', 12.4)
<class 'str'> <class 'str'> <class 'float'>A name, an outcome and a runtime. Chapter 5.1 warned that a list mixing types is usually a record in disguise and suggested that Module 6 had a better tool — this is that tool. Here the mixed types are not a smell; they are the record's three fields.
Order is part of the value, exactly as it was for lists:
print((1, 2) == (1, 2))
print((1, 2) == (2, 1))True
FalseAnd a tuple is never equal to a list, even with the same contents in the same order:
print((1, 2) == [1, 2])FalseThey are different kinds of value, and == says so. That is worth knowing before you ever compare data that arrived from two different places.
Duplicates are kept, and membership works as it did for lists — whole elements, not substrings:
sig = ("clk", "reset_n", "valid")
print("clk" in sig)
print("cl" in sig)True
False"cl" is False because it is not one of the three elements. That is Chapter 5.1's rule, unchanged.
Tuples nest, too:
pair = (("clk", 1), ("data", 32))
print(len(pair))
print(pair[0])2
('clk', 1)Two elements, each of which is itself a tuple of two. Chapter 5.7's rule applies without modification: each bracket applies to whatever is on its left.
4. What You Cannot Do
A tuple cannot be changed after it is created. Here is the one line of evidence; Chapter 6.4 is the chapter that explains it properly:
job = ("axi_burst", 48210)
job[0] = "reg_rw"TypeError: 'tuple' object does not support item assignmentYou will recognise that message. It is word-for-word what Chapter 4.11 showed for a string, with tuple in place of str — because it is the same rule. A tuple, like a string, is immutable.
There is no append, no insert, no remove, no sort. Those were list methods and a tuple does not have them, because every one of them changes a collection's contents.
5. Tuples Are Everywhere Already
One reason to learn this now rather than later: Python itself hands you tuples, and you have already seen one without being told.
Chapter 4.10 showed partition and said it gave back "three pieces grouped together" with a pointer to Module 6:
line = "UVM_ERROR: scoreboard mismatch"
print(line.partition(": "))('UVM_ERROR', ': ', 'scoreboard mismatch')That is a tuple. Three parts, in a fixed order, from one operation — exactly the shape a tuple is for. partition always returns three pieces, so a fixed record is the honest thing for it to return.
Chapter 4.10 also showed endswith accepting several options grouped in extra parentheses. Those too were tuples.
6. The Capability Immutability Unlocks
Now the payoff the canonical curriculum names for this chapter, and it is worth seeing even though the structure it involves belongs to a later module.
Python has a collection that looks things up by a key you choose rather than by position. It is called a dictionary, and Module 8 teaches it properly. Here it appears only to make one point.
A tuple can be a key:
lookup = {("smoke", 1234): "PASS"}
print(lookup[("smoke", 1234)])PASSA list cannot:
lookup = {["smoke", 1234]: "PASS"}TypeError: unhashable type: 'list'The reason is immutability. A key has to stay the same for the lookup to keep working — if the thing you filed something under could change afterwards, you would no longer be able to find what you filed. Python enforces that by refusing mutable values as keys, and the word in the error, unhashable, is its name for "cannot be used as a key".
Everything else about dictionaries — how to build one, read from one safely, update one — is Module 8's. The only thing to take from this section is which kinds of value are allowed to be keys, and why.
7. Predict, Run, Observe
Predict all six before reading on.
a = ("clk", 1)
b = "clk", 1
c = ("PASS", "FAIL", "PASS")
print(type(b))
print(a == b)
print(len(c))
print("PASS" in c)
print(("clk", 1) == ("1", "clk"))
print(len(("clk", 1, ("a", "b"))))The verified output:
<class 'tuple'>
True
3
True
False
3b is a tuple despite having no parentheses — Section 2. a == b is True because they hold the same values in the same order, and the parentheses on one of them changed nothing about the value.
len(c) is 3 with a duplicate counted, and membership finds "PASS".
The fifth is False on both counts: different order and 1 is not "1".
The last is 3, not 4. The tuple has three elements, the third of which is itself a tuple — len() counts at one level, exactly as Chapter 5.7 established for nested lists.
8. Exercises
Exercise 1 — write three records. Create and print: a tuple holding a signal name and its width, a tuple holding a test name, an outcome and a runtime, and an empty tuple. Print the length of each.
Exercise 2 — comma or parentheses. Without running anything, give the type of each, then verify:
(a) (1, 2) (b) 1, 2 (c) () (d) ("a",) (e) ("a")
Two of those are not tuples. Say which, and which token decides it.
Exercise 3 — predict equality. Say True or False for each and explain the two that are not about ordering:
(a) (1, 2) == (1, 2) (b) (1, 2) == (2, 1) (c) (1, 2) == [1, 2] (d) ("1", 2) == (1, 2)
Exercise 4 — record or list. For each, say whether you would reach for a tuple or a list, in one sentence each: (a) the tests still to run (b) a screen coordinate (c) the failures found so far (d) a signal's name and bit width (e) the lines of a log file
Exercise 5 — the key rule. Explain in two sentences why Python refuses a list as a dictionary key but accepts a tuple. Your answer should mention what would go wrong if mutable keys were allowed.
Exercise 6 — nested length. Predict len(t) for t = ("clk", ("a", "b", "c")), then verify, and explain the answer in one sentence.
Exercise 7 — find the tuple you already met. Run print("a:b".partition(":")) and say what type it returns, how many elements it has, and why a fixed record is the right shape for that operation's result.
9. Summary
- A tuple is an ordered collection whose contents cannot be changed after it is created.
- It represents a record: a fixed set of parts whose positions have stable meaning, not a collection that happens not to be growing right now.
- The comma makes the tuple; the parentheses group it.
10, 20is a tuple. The one exception is(), the empty tuple. len(),in, indexing and nesting all behave as they did for lists — one idea reused, not a new system.- A tuple is never equal to a list, even with identical contents.
- A tuple has no
append,insert,removeorsort, and item assignment isTypeError: 'tuple' object does not support item assignment— the same message shape as a string. - Python already hands you tuples:
partition()returns one, and the grouped optionsendswith()accepts are one. - Immutability is a qualification, not a limitation. A tuple can be a dictionary key where a list raises
TypeError: unhashable type: 'list', because a key must not be able to change.
The next chapter is the smallest piece of syntax in the module and the one that catches everyone.
Where this fits
Part of the Python curriculum.
