Lists and loops
Store ordered collections, access positions and slices, repeat work, and count correct predictions with explicit conditions.
Work here, beside the explanation
A list is the typed counterpart of a collection in your block program. Its order matters: the first prediction must still describe the first input. Build the list, read its positions, repeat work, and then count predictions. Python starts list indexes at zero; the friendly list-item block in Level 3 starts at one. Keep that deliberate difference in view.
Each numbered stage below shows a complete program. Try this stage copies it into the editor beside the article, including every line it needs from earlier stages, so it works even after you reload the page. Read the program first, predict what it will print, then press Run. Loading a stage replaces what is in the editor; Undo brings your own version back.
Build with me · 1
1. Make one ordered collection
Square brackets enclose a list and commas separate its values. Here one name, labels, refers to four integers in order. len(labels) returns the count of elements, four. It does not return the highest value or the final index. A list can be empty ([]) and can contain repeated values. The two eights are two observations; Python does not remove them. This is the same reason repeated examples remain separate rows in a dataset.
labels = [3, 8, 2, 8]print(labels)print("How many:", len(labels))Run and compare the displayed collection with the four source values.
What to look for
The list is [3, 8, 2, 8] and its length is 4.
Make it yours
Choose four different labels between 0 and 9, including one repeated value.
Build with me · 2
2. Read individual positions
An index selects one element. Index zero selects the first, one the second, and negative one the last. With four elements, valid nonnegative indexes are 0, 1, 2, and 3. labels[4] is therefore outside the list. The count and final index differ by one because counting starts at zero. Keeping that distinction explicit prevents selecting the wrong true label when comparing predictions.
labels = [3, 8, 2, 8]print("First:", labels[0])print("Second:", labels[1])print("Last:", labels[-1])Predict each line before running. Point to the matching value in the list.
What to look for
The first, second, and last displayed values are 3, 8, and 8.
Make it yours
Try index 3, then briefly try index 4 and inspect IndexError. Restore a valid index.
Build with me · 3
3. Take a slice, which remains a list
A slice selects a range. The start is included and the stop is excluded, so [1:3] takes positions 1 and 2. Omitting the start means begin at zero. Indexing [0] produces one integer; slicing [:1] produces a list containing one integer. The printed square brackets reveal the difference. Later, a model needs a batch containing one image rather than a bare image, and this same distinction appears in array shapes.
labels = [3, 8, 2, 8]print("Middle:", labels[1:3])print("First two:", labels[:2])print("One value:", labels[0])print("A list with one value:", labels[:1])Run and identify which outputs are lists and which output is a single value.
What to look for
Middle is [8, 2], first two is [3, 8], one value is 3, and its one-element list is [3].
Make it yours
Change the slice bounds and explain why the stop element is excluded.
Build with me · 4
4. Grow a collection deliberately
The dot in predictions.append(3) requests the append method belonging to this list. A method is a function associated with an object. Append changes the existing list by adding one value at its end. It returns None, so writing predictions = predictions.append(3) would replace your useful list with None. That is a common beginner mistake: changing an object and returning a new object are different operations.
predictions = []predictions.append(3)predictions.append(8)print(predictions)print("Count:", len(predictions))Run, then add a third append line before the display.
What to look for
The original program displays [3, 8] and a count of 2; your added value increases the count by one.
Make it yours
Start with an empty list named favourite_digits and append your own choices.
Build with me · 5
5. Translate a for-each block
The for statement takes each value in labels and gives the current value the local working name label. The colon introduces the body; four spaces put print inside it. Finished is aligned with for, so it runs after the loop, once. In the block editor the surrounding repeat or for-each block showed the body. Here indentation draws that boundary. The singular name label is a convention that helps readers distinguish one item from the collection labels.
labels = [3, 8, 2, 8]for label in labels: print("Label:", label)print("Finished")Count the lines you expect before running. Then inspect the indentation.
What to look for
Four Label lines appear, followed by one Finished line.
Make it yours
Add a second indented display inside the loop and predict how many times it will run.
Build with me · 6
6. Put a decision inside repetition
The counter is initialised before the loop so earlier matches survive each iteration. The if statement is one indentation level inside the loop, and the counter change is two levels inside because it belongs to both structures. == compares rather than assigns. When the current label is not eight, Python skips the increment and continues with the next value. Moving count = 0 inside the loop would repeatedly erase the total.
labels = [3, 8, 2, 8]count = 0for label in labels: if label == 8: count = count + 1print("Eights:", count)Trace the counter after each label: 0, 1, 1, then 2. Run to check.
What to look for
The final line is Eights: 2.
Make it yours
Choose a different wanted label and rename the output so it describes your question.
Build with me · 7
7. Keep predictions paired with truth
range(len(truth)) supplies positions 0 through 3. The same index selects the prediction and true label for one example. += 1 is shorthand for adding one and assigning the result back. Matching lengths are necessary but insufficient: both lists must still refer to examples in the same order. Sorting predictions would break that connection even if it kept four entries. Later we retain IDs to protect the same relationship when exporting files.
truth = [3, 8, 2, 6]predictions = [3, 1, 2, 6]correct = 0for i in range(len(truth)): print("Position", i, "truth", truth[i], "prediction", predictions[i]) if predictions[i] == truth[i]: correct += 1print("Correct:", correct, "of", len(truth))Read the position-by-position display and identify the one mismatch before checking the total.
What to look for
Position 1 disagrees; the final total is three correct out of four.
Make it yours
Change exactly one prediction and explain how the total should change. Never reorder only one list.
Build with me · 8
8. Traverse rows and pixels
A list can contain other lists. The outer loop chooses one row, and the inner loop visits the pixels in that row. The named argument end=" " asks print to finish with a space instead of its usual newline. The empty print after the inner loop starts the next row. It is indented inside the outer loop, but outside the inner loop, so each row gets exactly one newline. This small grid is an image made of numerical brightness values.
image = [[0, 1, 0], [1, 1, 1]]for row in image: for pixel in row: print(pixel, end=" ") print()Run, then draw boxes around the two loop bodies in your notes or trace their indentation aloud.
What to look for
Two rows appear, each containing three numbers.
Make it yours
Design a three-by-three symbol by editing zeros and ones. Keep every row the same width.
Build with me · 9
9. Build a complete evaluation
This combines a list, a loop, a decision, a running total, and a calculation. The two checks reject mismatched lengths and an empty evaluation. raise ValueError(...) deliberately stops with a helpful message when an assumption is broken; it is better than computing a misleading number. The program still cannot prove the lists belong in the same order. That meaning must come from how you prepared the data. The final ratio uses the number evaluated as its denominator.
truth = [3, 8, 2, 6]predictions = [3, 1, 2, 6]if len(truth) != len(predictions): raise ValueError("Prediction and truth counts differ.")if len(truth) == 0: raise ValueError("Provide at least one example.")correct = 0wrong_positions = []for i in range(len(truth)): if predictions[i] == truth[i]: correct += 1 else: wrong_positions.append(i)accuracy = correct / len(truth)print("Correct:", correct, "of", len(truth))print("Accuracy:", accuracy)print("Wrong positions:", wrong_positions)Build and run the complete version, then test the length check by adding an unmatched prediction. Repair the data afterward.
What to look for
The supplied example reports 3 of 4, accuracy 0.75, and wrong positions [1].
Make it yours
Add one new matched pair of values to both lists. Predict the new accuracy before running.
Keep examples aligned
A list has an order, and its first item is at index zero. A loop visits items in that order unless your code explicitly changes it. When two lists describe the same examples, such as predictions and true labels, matching positions must continue to refer to the same image. A correct count from misaligned lists is meaningless. Before using thousands of rows, test your loop on a few values whose answer you can work out by hand.
The complete reference is folded away below. Compare it with your work after trying the steps; changing a personal choice such as a name, a colour, or a display threshold can produce a different valid program.
Full reference solution
This is the final complete program built in the walkthrough. All its setup is included. Personal choices may differ in your own version; model scores are measured when you run, not promises about a future dataset.
truth = [3, 8, 2, 6]predictions = [3, 1, 2, 6]if len(truth) != len(predictions): raise ValueError("Prediction and truth counts differ.")if len(truth) == 0: raise ValueError("Provide at least one example.")correct = 0wrong_positions = []for i in range(len(truth)): if predictions[i] == truth[i]: correct += 1 else: wrong_positions.append(i)accuracy = correct / len(truth)print("Correct:", correct, "of", len(truth))print("Accuracy:", accuracy)print("Wrong positions:", wrong_positions)Compare this with your version. Different names and personal choices are fine when the program follows the same logic.
Keep your progress
Sign in and every reading, quiz, and exercise you finish is saved.