The body of a loop can contain another loop. In this code, the inner loop is executed once for each item in the outer list:
| | >>> outer = ['Li', 'Na', 'K'] |
| | >>> inner = ['F', 'Cl', 'Br'] |
| | >>> for metal in outer: |
| | ... for halogen in inner: |
| | ... print(metal + halogen) |
| | ... |
| | LiF |
| | LiCl |
| | LiBr |
| | NaF |
| | NaCl |
| | NaBr |
| | KF |
| | KCl |
| | KBr |
The number of times that function print is called is len(outer) * len(inner). The following table shows that for each iteration of the outer loop (in other words, for each item in outer), the inner loop executes three times (once for each item in inner).
| Iteration of | What metal | Iteration of | What halogen | What Is Printed |
|---|---|---|---|---|
| 1st | outer[0] | 1st | inner[0] | LiF |
|
| 2nd | inner[1] | LiCl | |
|
| 3rd | inner[2] | LiBr | |
| 2nd | outer[1] | 1st | inner[0] | NaF |
|
| 2nd | inner[1] | NaCl | |
|
| 3rd | inner[2] | NaBr | |
| 3rd | outer[2] | 1st | inner[0] | KF |
|
| 2nd | inner[1] | KCl | |
|
| 3rd | inner[2] | KBr |
Loops and conditionals can be nested inside one another
Sometimes an inner loop uses the same list as the outer loop. An example of this is shown in a function used to generate a multiplication table. After printing the header row, use a nested loop to print each row of the table in turn, using tabs (see Table 2, ) to align the columns:
| | def print_table(n: int) -> None: |
| | """Print the multiplication table for numbers 1 through n inclusive. |
| | |
| | >>> print_table(5) |
| | 1 2 3 4 5 |
| | 1 1 2 3 4 5 |
| | 2 2 4 6 8 10 |
| | 3 3 6 9 12 15 |
| | 4 4 8 12 16 20 |
| | 5 5 10 15 20 25 |
| | """ |
| | # The numbers to include in the table. |
| | numbers = range(1, n + 1) |
| | |
| | # Print the header row. |
| | for i in numbers: |
| | print(f'\t{i}', end='') |
| | |
| | # End the header row. |
| | print() |
| | |
| | # Print each row number and the contents of each row. |
| ① | for i in numbers: |
| ② | print (i, end='') |
| ③ | for j in numbers: |
| ④ | print(f'\t{i * j}', end='') |
| | |
| | # End the current row. |
| ⑤ | print() |
Each iteration of the outer loop prints a row. Each row consists of a row number, n tab-number pairs, and a newline. It’s the inner loop’s job to print the tabs and numbers part of the row. For print_table(5), let’s take a closer look at what happens during the third iteration of the outer loop:
i is assigned 3, the third item of numbers.
The row number, 3, is printed.
This line of code is the inner loop header, and it will be executed five times. Before the first iteration of the inner loop, j is assigned 1; before the second iteration, it is assigned 2; and so on, until it is assigned 5 before the last iteration.
Five times this line is executed right after the previous line, using whatever value j was just assigned. The first time it prints a tab followed by 3, then a tab followed by 6, and so on until it prints a tab followed by 15.
Now that a row has been printed, the program prints a newline. This line of code is executed outside of the inner loop, ensuring it is executed only once per row.
In addition to looping over lists of numbers, strings, and Booleans, you can also loop over lists of lists. Here is an example of a loop over an outer list. The loop variable, which we’ve named inner_list, is assigned an item of nested list elements at the beginning of each iteration:
| | >>> elements = [['Li', 'Na', 'K'], ['F', 'Cl', 'Br']] |
| | >>> for inner_list in elements: |
| | ... print(inner_list) |
| | ... |
| | ['Li', 'Na', 'K'] |
| | ['F', 'Cl', 'Br'] |
To access each string in the inner lists, you can loop over the outer list and then over each inner list using a nested loop. Here, Python prints every string in every inner list:
| | >>> elements = [['Li', 'Na', 'K'], ['F', 'Cl', 'Br']] |
| | >>> for inner_list in elements: |
| | ... for item in inner_list: |
| | ... print(item) |
| | ... |
| | Li |
| | Na |
| | K |
| | F |
| | Cl |
| | Br |
In the previous code, the outer loop variable, inner_list, refers to a list of strings, and the inner loop variable, item, refers to a string from that list.
When you have a nested list, and you want to do something with every item in the inner lists, you need to use a nested loop.
Nothing says that nested lists have to be the same length:
| | >>> info = [['Isaac Newton', 1643, 1727], |
| | ... ['Charles Darwin', 1809, 1882], |
| | ... ['Alan Turing', 1912, 1954, '[email protected]']] |
| | >>> for item in info: |
| | ... print(len(item)) |
| | ... |
| | 3 |
| | 3 |
| | 4 |
Nested lists with inner lists of varying lengths are referred to as ragged lists. Ragged lists can be challenging to process if the data isn’t uniform; for example, trying to assemble a list of email addresses from data where some addresses are missing requires careful consideration.
Ragged data does arise normally. For instance, if a daily record is made of the time at which a person has a drink of water, each day will have a different number of entries:
| | >>> drinking_times_by_day = [["9:02", "10:17", "13:52", "18:23", "21:31"], |
| | ... ["8:45", "12:44", "14:52", "22:17"], |
| | ... ["8:55", "11:11", "12:34", "13:46", |
| | ... "15:52", "17:08", "21:15"], |
| | ... ["9:15", "11:44", "16:28"], |
| | ... ["10:01", "13:33", "16:45", "19:00"], |
| | ... ["9:01", "12:24", "18:51", "23:13"]] |
| | >>> for day in drinking_times_by_day: |
| | ... for drinking_time in day: |
| | ... print(drinking_time, end=' ') |
| | ... print() |
| | ... |
| | 9:02 10:17 13:52 18:23 21:31 |
| | 8:45 12:44 14:52 22:17 |
| | 8:55 11:11 12:34 13:46 15:52 17:08 21:15 |
| | 9:15 11:44 16:28 |
| | 10:01 13:33 16:45 19:00 |
| | 9:01 12:24 18:51 23:13 |
The inner loop iterates over the items of day, and the length of that list varies.