- Learn
- Computer Science & IT
- Programming
- Introduction to Programming with Python
- Python Lists and Tuples
Lists and Tuples in Python
sort(), sorted() and key functions.BeginnerLesson 6 of 10 in Python for Beginners: Introduction to Programming
What you will learn
- Create lists, read single items and slices by index, and combine and summarize lists with Python's operators and built-in functions.
- Create a list and read its items by indexWrite list literals, build lists with list(), measure them with len(), read items with positive and negative indices, and test membership with in.
- Slice a listTake part of a list with start:stop:step slices, predict the result when values are omitted, negative or out of range, and tell a slice apart from a single item.
- Combine and summarize lists with operators and built-in functionsJoin and repeat lists with + and *, compare lists, compute totals, extremes and averages with sum(), min() and max(), and convert between strings and lists.
- Create a list and read its items by index
- Add, insert, remove, find and replace items in a list, and use each method's effect and return value correctly.
- Add and remove itemsGrow and shrink a list with append(), extend(), insert(), pop(), remove(), del and clear(), and tell their effects and return values apart.
- Find, count and replace itemsLocate values with index(), count() and in, and replace single items or whole ranges by assigning to an index or a slice.
- Add and remove items
- Visit every item of a list with loops, apply counting, totaling, searching, filtering and transforming patterns, and work with lists of lists as tables.
- Loop over items and positionsChoose between looping over items, over indices with range(len()), or over both with enumerate() and zip(), and change a list safely while processing it.
- Apply common list-processing patternsTotal, count, find extremes, search, filter and transform the items of a list with loops, and recognize when a built-in function does the same job.
- Work with nested listsStore a table as a list of rows, read and change cells with two indices, and visit every cell with nested loops.
- Loop over items and positions
- Store fixed groups of values in tuples, decide when a tuple fits better than a list, and unpack sequences into separate variables.
- Create tuples and choose between tuples and listsWrite tuples, including empty and one-item tuples, read them by index and slice, and explain what their immutability allows and forbids.
- Pack and unpack valuesAssign several variables at once from a tuple or list, swap two values, collect the remaining values with a starred name, and return several values from a function.
- Create tuples and choose between tuples and lists
- Predict how a change made through one variable shows up in others, copy lists when independence is needed, and pass lists to functions without surprises.
- Tell names, objects and aliases apartExplain that variables refer to objects, recognize when two names share one list, and distinguish identity (is) from equality (==) and mutation from rebinding.
- Copy lists and avoid shared inner listsMake an independent copy with slicing, list() or copy(), recognize when a shallow copy still shares nested lists, and use a deep copy when it must not.
- Pass lists to functions and return themPredict when a function changes the caller's list, choose between changing a list in place and returning a new one, and avoid a mutable default argument.
- Tell names, objects and aliases apart
- Put data in order with sort() and sorted(), ascending or descending, and control the order with key functions and the way tuples compare.
- Sort with sort() and sorted()Choose between sorting a list in place and making a sorted copy, sort in descending order, tell reversing from sorting, and predict how numbers and strings are ordered.
- Sort by a key and sort recordsSort by a computed key such as length or lowercase text, sort lists of tuples by one or several fields, and use the fact that Python's sort is stable.
- Sort with sort() and sorted()
Python Lists and Tuples study guide
1Create and read lists
A list gives a program one place to keep an ordered collection, such as scores or names. Its positions let you reach a particular item, while slices let you select a run of items or step through a pattern. Creating, reading and combining lists involves several different result types: a single item, a new list, a number or a string. Following those results makes it easier to choose the next operation and spot a boundary error.
1.1 Create a list and read a position
A list keeps values in a chosen order. Write the items between square brackets, with commas between them. Each item has a position, so repeated values still occupy separate places.
Build and measure a list
scores = [88, 92, 75]
print(scores)
print(len(scores))
Output:
[88, 92, 75]
3
len() counts items, not the largest value or the final position. Lists can contain mixed types, as in [3, "three", 3.0, True], although keeping related data together usually makes processing easier. [] and list() both create an empty list. Its length is 0, and it can grow as the program collects values.
list() can also collect the items of an iterable, an object a for loop can walk through. list(range(4)) gives [0, 1, 2, 3]. list("cat") gives ['c', 'a', 't']: the string supplies one character at a time. The result is a new list.
Count positions from zero
An index identifies one position. Python starts at 0, so the three scores have indices 0, 1 and 2.
| Expression | Result | Position |
|---|---|---|
scores[0] | 88 | First |
scores[1] | 92 | Second |
scores[2] | 75 | Third |
scores[-1] | 75 | Last |
scores[-2] | 92 | Second from last |
scores[-3] | 88 | Third from last |
Negative indices count backward from the end. For a list of length n, the valid indices run from -n through n - 1. The last item is scores[len(scores) - 1], or more simply scores[-1]. -0 is still 0; it does not mean the last position.
Recognize an invalid index
scores[3] raises IndexError because no fourth item exists. scores[len(scores)] makes the same mistake: the count is one greater than the last nonnegative index. An empty list has no valid item index, including -1.
A list index must be an integer, not a float. scores[1.0] raises TypeError, even though 1.0 has a whole-number value. / produces a float, so scores[len(scores) / 2] also fails. With this three-item list, len(scores) // 2 produces the integer 1, and scores[1] is 92.
Ask whether a value occurs
Membership checks values, not positions:
colors = ["red", "green"]
print("green" in colors)
print("Green" in colors)
print("blue" not in colors)
Output:
True
False
True
in and not in return Boolean values and work on empty lists too. String comparisons are case-sensitive, so "Green" and "green" do not match. A membership test is useful before an operation that requires a value to be present, such as removing it or finding its position.
Key Takeaways
- Lists preserve order and may contain repeated values.
len(values)counts items; the last nonnegative index islen(values) - 1.- Negative indices count from the end, starting at
-1. - An invalid item index raises
IndexError; a float index raisesTypeError. intests whether an equal value occurs in the list.
1.2 Take a slice of a sequence
A slice selects a sequence of items and returns a new sequence. For a list, the result is another list, even when it contains only one item or no items.
Include the start and leave out the stop
letters = ["a", "b", "c", "d", "e", "f"]
print(letters[1:4])
Output:
['b', 'c', 'd']
The positions selected are 1, 2 and 3. Position 4 is the stopping boundary, so 'e' is left out. With a step of 1 and bounds satisfying 0 <= start <= stop <= len(letters), the number of selected items is stop - start. Here it is 3. letters[4:2] gives [] because a forward slice cannot reach an earlier stop.
Leave out a boundary
| Slice | Meaning | Result |
|---|---|---|
letters[:2] | First two items | ['a', 'b'] |
letters[4:] | From position 4 to the end | ['e', 'f'] |
letters[:] | All items in a new list | ['a', 'b', 'c', 'd', 'e', 'f'] |
letters[-2:] | Last two items | ['e', 'f'] |
letters[:-1] | All except the last | ['a', 'b', 'c', 'd', 'e'] |
Negative bounds count from the end just as negative indices do. letters[:n] and letters[n:] divide the list at one boundary. Joining those two slices rebuilds its contents in their original order.
Control the step
The full form is values[start:stop:step]. A step of 2 selects a position, skips one and selects the next. letters[::2] gives ['a', 'c', 'e'], while letters[1::2] gives ['b', 'd', 'f'].
A negative step moves backward. letters[::-1] starts at the last item and produces ['f', 'e', 'd', 'c', 'b', 'a']. For a bounded backward slice, letters[4:1:-1] visits indices 4, 3 and 2, giving ['e', 'd', 'c']; the stop is still excluded. A step of 0 raises ValueError because it cannot move to another position.
Separate a boundary from a position
Slice bounds may extend past either end. Python cuts them back: letters[4:100] is ['e', 'f'], and letters[10:] is []. These slices do not raise IndexError. Reading the single item letters[10] does.
letters[2] is the string 'c'. letters[2:3] is the list ['c']. The colon changes the kind of result, which matters when later code expects a string or a list.
Work with the result
After first_three = letters[:3], assigning first_three[0] = "z" changes only that new outer list; letters[0] stays 'a'. A full slice is a shallow copy, so nested mutable items can still be shared.
Strings and tuples follow the same boundary and step rules. The result keeps the original sequence type: "python"[1:4] gives 'yth', and (10, 20, 30)[1:] gives (20, 30).
Key Takeaways
- A slice includes its start and excludes its stop.
- Omitted bounds select through the appropriate end of the sequence.
- The step controls direction and spacing; zero is invalid.
- Out-of-range slice bounds are clipped.
- An item lookup returns one item; a slice returns a sequence.
- A list slice makes a new outer list.
1.3 Combine values and calculate summaries
Lists support operators for building sequences and functions for summarizing their values. Check whether an operation creates a new list, produces a number or returns text: those results serve different jobs.
Join or repeat lists
+ joins two lists and creates a new list. [1, 2] + [3] gives [1, 2, 3] without changing either input. Both operands must be lists: [1, 2] + 3 raises TypeError. Put a single extra value in a one-item list when using +.
* repeats the sequence. [0] * 4 gives [0, 0, 0, 0], and ["ab", "cd"] * 2 gives ['ab', 'cd', 'ab', 'cd']. It repeats items, not the characters inside each string. A zero or negative repetition count gives []. counts = [0] * 7 provides seven starting counters. Repeating an inner list shares it across positions, which matters when those rows are changed later.
Total, extremes and average
| Expression | Result |
|---|---|
sum([4, 8, 15]) | 27 |
min([4, 8, 15]) | 4 |
max([4, 8, 15]) | 15 |
sum([]) | 0 |
sum() adds numbers. It does not join strings; sum(["a", "b"]) raises TypeError. min() and max() find the smallest and largest items, so the items must support comparison with each other. All-string lists work: max(["pear", "apple"]) gives 'pear' through character-by-character ordering. An empty list has no minimum or maximum and raises ValueError for either call.
The mean is the total divided by the number of items:
temps = [18.5, 21.0, 19.5, 23.0]
if temps:
total = sum(temps)
mean = total / len(temps)
print(total, mean)
Output:
82.0 20.5
The condition works because empty lists count as false and nonempty lists as true. Without the guard, averaging [] would divide by zero and raise ZeroDivisionError. Choose what the program should do when no readings exist, such as return None.
Compare sequences in order
== checks matching items in matching positions. [1, 2, 3] == [1, 2, 3] is True; [1, 2, 3] == [3, 2, 1] is False.
For < and >, compare from the left and stop at the first unequal pair. [2, 9] < [3, 0] is True because 2 is less than 3. The 9 and 0 do not decide anything. When one list is the beginning of another, the shorter one comes first: [2] < [2, 0] is True.
Move between text and lists
colors = "red,green,blue".split(",")
print(colors)
print(", ".join(["red", "green"]))
Output:
['red', 'green', 'blue']
red, green
split() divides a string at its separator. join() is called on the separator and places it between the strings supplied. Every item must be a string. To join numbers, first build a list of their str() results; passing [1, 2] directly to join() raises TypeError.
Key Takeaways
+joins lists;*repeats their sequence of items.sum,minandmaxproduce summary values.- Guard an empty list before calculating a mean or an extreme.
- Sequence comparison uses item order and the first unequal pair.
splitcreates text pieces; a separator’sjoincombines strings.
2Change a list
A shopping list grows, a queue loses its first item, and a recorded price needs a correction. Python provides list methods and assignment for these changes. The choice depends on whether you know a value or a position, whether you need one item or several, and whether you need to keep a removed item. Paying attention to a method’s return value prevents a change to the list from accidentally replacing its name with None.
2.1 Add and remove list items
Lists are mutable: a program can change their contents after creating them. A method belongs to an object and is called with a dot, as in cart.append("eggs"). Its effect on the list and its return value are two separate things.
Add one item or several
cart = ["milk"]
cart.append("eggs")
cart.extend(["tea", "jam"])
print(cart)
Output:
['milk', 'eggs', 'tea', 'jam']
append(x) adds exactly one item at the end. If x is a list, that whole list becomes one nested item. Starting with ['milk', 'eggs'], cart.append(["tea", "jam"]) produces ['milk', 'eggs', ['tea', 'jam']], of length 3.
extend(iterable) adds the items supplied by the iterable separately. Extending with ["tea", "jam"] makes the cart length 4. Extending with "ab" adds 'a' and 'b' separately; append the string to keep 'ab' as one item.
insert(i, x) adds an item before the current position i. After nums = [10, 30] and nums.insert(1, 20), the list is [10, 20, 30]. Later items shift right. insert(0, x) adds at the front; an index past the end adds at the end without an index error.
Remove by position or value
| Operation | Uses | Returns |
|---|---|---|
items.pop() | Last position | Removed item |
items.pop(i) | Position i | Removed item |
items.remove(x) | First value equal to x | None |
del items[i] | Position i | No return value |
del items[start:stop] | Slice of positions | No return value |
items.clear() | Whole list | None |
With nums = [10, 20, 30], last = nums.pop() saves 30 and leaves [10, 20]. nums.pop(0) then returns 10 and leaves [20]. An empty list or invalid position makes pop() raise IndexError.
remove() takes a value. With pets = ["cat", "dog", "cat"], pets.remove("cat") leaves ['dog', 'cat']. Only the first match disappears. If the value is missing, remove() raises ValueError. Use a membership check when it may be absent. To remove every 'cat', use:
while "cat" in pets:
pets.remove("cat")
With [5, 0, 7], remove(0) removes the value 0 and leaves [5, 7]; pop(0) removes the value at position 0, giving [0, 7]. The argument's meaning determines the method.
del can delete a range: from [5, 6, 7, 8], del nums[1] leaves [5, 7, 8], and del nums[0:2] then leaves [8]. clear() leaves the existing list empty.
Keep the return value straight
append, extend, insert, remove and clear return None. Write cart.append("tea") on its own line. Writing cart = cart.append("tea") makes cart refer to None; a later cart.append("jam") raises AttributeError. Save a method result only when it provides a value the program needs, as last = cart.pop() does.
Key Takeaways
appendadds one item;extendadds each supplied item.insertadds before a position and shifts later items.popremoves by position and returns the item.removedeletes the first equal value and fails if it is absent.deldeletes positions or slices;clearempties the same list.- Methods such as
appendreturnNone, so do not assign that result back to the list.
2.2 Find values and replace items
Finding a value, counting it and replacing it are different operations. Use a membership test when you need a yes-or-no result, a search method when you need a position, and assignment when you want the list to change.
Find the first matching position
days = ["Mon", "Tue", "Wed", "Tue"]
print(days.index("Tue"))
print(days.index("Tue", 2))
print(days.count("Tue"))
print(days.count("Sun"))
Output:
1
3
2
0
index(x) returns the first position containing a value equal to x. Its optional start argument tells Python where to begin searching. days.index("Tue", 2) skips the match at position 1 and finds the one at position 3. The answer remains an index into the whole list, not a count from the new starting point.
index() raises ValueError when the value is absent. Lists have no find() method that returns -1. If a missing value is expected, test membership first:
if "Sun" in days:
position = days.index("Sun")
print(position)
This code prints nothing because 'Sun' is absent. count(x) can be used without that guard: it returns 0 when there are no matches. These operations use equality, so [1, 2.0].count(2) is 1. Text still respects case: 'tue' does not equal 'Tue'.
Replace one existing item
prices = [4.5, 3.0, 7.25]
prices[1] = 3.5
print(prices)
Output:
[4.5, 3.5, 7.25]
The old second value is overwritten and the length stays 3. The index must exist: prices[3] = 1.0 raises IndexError. To add at the end, use append().
| Statement | Effect on [10, 20] |
|---|---|
nums[0] = 99 | [99, 20] |
nums.insert(0, 99) | [99, 10, 20] |
Replacement uses an existing slot. Insertion creates an extra slot before the selected position.
Replace a range with slice assignment
nums = [1, 2, 3, 4, 5]
nums[1:3] = [20, 30, 40]
print(nums)
nums[0:2] = []
print(nums)
Output:
[1, 20, 30, 40, 4, 5]
[30, 40, 4, 5]
The first assignment replaces the two items at indices 1 and 2 with three new items, growing the list by one. An ordinary contiguous slice can be replaced with a shorter or longer sequence. Assigning [] deletes the selected range. This changes the original list; it is different from reading a slice into a new variable.
Edit text by building new text
A string is immutable, so word = "cat" followed by word[0] = "b" raises TypeError. Build a new string with word = "b" + word[1:], or make a list of characters, change it and join it:
letters = list("cat")
letters[0] = "b"
word = "".join(letters)
print(word)
Output:
bat
Key Takeaways
indexreturns the first matching position and raisesValueErrorfor a missing value.countreturns the number of equal items, including zero.- Item assignment replaces a slot that already exists.
- Contiguous slice assignment can change the length of a list.
- Strings must be rebuilt instead of changed by item assignment.
3Process lists with loops
Loops turn a stored collection into useful results: a total, a matching position, a filtered list or a changed table. Each task starts by choosing what to carry through the loop and which information the loop needs from each item. Some tasks need only values, others need positions or paired records. Nested lists add one more level to follow, so processing a table means working through its rows and then its cells.
3.1 Walk through items and positions
A loop can use a list's values, its positions or both. Pick the form that supplies what the loop body needs. For a change to the list, also check whether the statement changes an item or only rebinds a local name.
Use items directly
for name in ["Ana", "Ben"]:
print("Hi", name)
Output:
Hi Ana
Hi Ben
The loop visits each item in order. On each pass, name refers to the current item. Assigning a different value to name does not replace that item in the list. In for r in readings: r = 0, only the name r changes.
Use positions to replace items
readings = [3, -1, 4, -5]
for i in range(len(readings)):
if readings[i] < 0:
readings[i] = 0
print(readings)
Output:
[3, 0, 4, 0]
range(len(readings)) supplies 0, 1, 2 and 3. At index 1, the condition is true, so item assignment replaces -1. At index 3, it replaces -5. Positive readings keep their values. Using range(len(readings) + 1) would also reach index 4, which does not exist.
Obtain a position and an item together
enumerate() supplies pairs. Unpack each pair in the loop header:
for i, name in enumerate(["Ana", "Ben"]):
print(i, name)
Output:
0 Ana
1 Ben
enumerate(names, start=1) supplies labels starting at 1 for a numbered display. Those labels are no longer the list's zero-based indices. To visit from last to first without changing the list, use for item in reversed(names):. For backward indices, use range(len(names) - 1, -1, -1); a three-item list gives 2, 1, 0.
Pair two lists
names = ["Ana", "Ben"]
scores = [90, 85]
for name, score in zip(names, scores):
print(name, score)
Output:
Ana 90
Ben 85
zip() pairs items at matching positions and stops at the shorter input. If every record matters, check the lengths before relying on it; an unmatched final name will otherwise be skipped.
Control an index with while
A while loop needs a starting index, a boundary check and a step:
i = 0
while i < len(readings):
print(readings[i])
i += 1
Forgetting the increment prevents this loop from finishing. Using <= reaches len(readings) and causes IndexError.
Avoid shifting items during a for loop
Removing items changes the positions of those that follow. With [1, 2, 2, 3], removing each encountered 2 while looping over that same list leaves [1, 2, 3]: the second 2 shifts into the position just visited. Loop over nums[:] if removals must affect the original, or build a new list of items to keep. Adding items to the list being visited can also make the loop behave unexpectedly.
Key Takeaways
- Use a direct loop for items,
range(len(...))for positions, andenumeratefor both. - Rebinding the loop variable does not replace a list item.
zipstops at the shorter input.reversedvisits backward without changing the list.- A
whileloop must advance its index and stop beforelen(values). - Build a new list or loop over a copy when removing items.
3.2 Build totals, searches and new lists
Many list problems use a few reusable loop patterns. Decide what result the program needs, set up that result before the loop and update it as each item arrives.
Accumulate a total or a count
sales = [120, 75, 205, 50]
total = 0
for sale in sales:
total += sale
print(total)
Output:
450
The running total becomes 120, 195, 400 and 450. Setting total = 0 inside the loop would erase previous work on every pass. sum(sales) performs this total directly.
A counter adds 1 for each qualifying item, not the item's value:
scores = [72, 45, 60, 88, 59]
passed = 0
for score in scores:
if score >= 60:
passed += 1
print(passed)
The output is 3: 72, 60 and 88 qualify. > 60 would give 2 because it excludes exactly 60. Keep the threshold's wording and comparison in agreement.
Find an extreme
For a nonempty list, initialize a running maximum from a real item:
temps = [-3, -8, -1, -5]
highest = temps[0]
for temp in temps[1:]:
if temp > highest:
highest = temp
print(highest)
Output is -1. Starting at 0 would wrongly keep 0 because all readings are lower. Use < to find the minimum, or use the built-ins min() and max(). Check for an empty list before accessing its first item.
Stop at the first match
values = [4, 0, -2, 5, -7]
position = -1
for i, value in enumerate(values):
if value < 0:
position = i
break
print(position)
The output is 2. -1 is a chosen signal for no match; do not use it as an index unless the search succeeded, because it is also a valid last-item index. break preserves the first matching position. Without it, later matches would overwrite the result.
x in values tests for one exact value, and values.index(x) finds its first position. A condition such as “is negative” needs a condition-based search like the loop above.
Filter or transform
A filter keeps selected original items:
passing = []
for score in scores:
if score >= 60:
passing.append(score)
print(passing)
Output is [72, 60, 88]; scores keeps all five items. A transformation computes one new item from each original:
nums = []
for text in ["3", "14", "15"]:
nums.append(int(text))
print(nums, sum(nums))
Output is [3, 14, 15] 32. The conversion happens before addition; summing the original strings fails.
Return a reusable result
def average(values):
if not values:
return None
return sum(values) / len(values)
average([18.5, 21.0, 19.5, 23.0]) returns 20.5. The empty case returns None without dividing by zero, and the function leaves the input list unchanged.
Key Takeaways
- Initialize an accumulator before the loop.
- A counter adds 1 per match; a total adds values.
- Start a running extreme from an actual item.
- Use
breakto keep the first match in a search. - Filtering selects items; transforming computes new values.
- A returning function lets the caller keep a result without changing the input.
3.3 Read and process a table of rows
A nested list is a list that contains other lists. A table commonly uses one inner list per row. Each lookup selects one level, so reading a cell takes two indices.
Select the row, then the cell
grid = [[1, 2, 3], [4, 5, 6]]
print(grid[1])
print(grid[1][2])
print(len(grid), len(grid[0]))
Output:
[4, 5, 6]
6
2 3
grid[1] selects the second row; [2] then selects that row's third item. len(grid) counts rows, while len(grid[0]) counts cells in the first row. This rectangular table has six cells. grid[2][1] fails at the first lookup because row 2 does not exist. Swapping row and column positions can select the wrong cell or raise IndexError.
Change a cell or a whole row
grid[0][1] = 20 changes the second cell in the first row, giving [[1, 20, 3], [4, 5, 6]]. grid[0] = [0, 0, 0] replaces the entire first row. The number of lookups shows which level is being replaced.
Visit every value
grid = [[1, 2, 3], [4, 5, 6]]
total = 0
for row in grid:
for value in row:
total += value
print(total)
Output:
21
The inner loop completes the first row before the outer loop supplies the second row. It adds 1, 2, 3, then 4, 5, 6. A column total uses one fixed position from each row:
column_total = 0
for row in grid:
column_total += row[1]
print(column_total)
The output is 7, from 2 and 5. This code requires each row to have a second item.
Rows do not have to be equally long. [[1], [2, 3]] is a valid nested list. Direct nested loops still visit every value because each inner loop follows its own row. Assuming all rows have len(grid[0]) items would miss values here. To count cells in such a table, add len(row) for every row.
Build independent rows
table = []
for r in range(3):
table.append([0] * 4)
table[0][0] = 1
print(table)
Output:
[[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
Each pass creates a new four-item list. The shortcut [[0] * 4] * 3 repeats a reference to one row; changing its first cell would appear in all three rows.
Store records
A row may describe one record instead of a row of numbers. With students = [["Ana", 90], ["Ben", 85]], students[1][0] is 'Ben' and students[1][1] is 85. When every record has two items, for name, score in students: unpacks them into useful names. Lists of tuples can represent the same kind of records.
Key Takeaways
- Two indices select a row and then a cell within that row.
len(grid)counts rows; row lengths may differ.- Nested loops process each row with its own inner loop.
- A column lookup requires that position to exist in every selected row.
- Create each mutable row separately to avoid shared cells.
4Use tuples and unpacking
Fixed groups of values often have meaningful positions: a point has coordinates, and a result record has a name and score. Tuples keep those positions fixed, while unpacking gives each value a useful name. These tools also explain how one assignment can swap two values and how a function can return several results. An immutable outer tuple can still contain a changeable list, so follow both the container and the objects inside it.
4.1 Choose a list or a tuple
A tuple stores items in order, like a list, but its positions cannot be replaced, added or removed. This is immutability. Tuples suit fixed groups such as coordinates, dates and records; lists suit collections that grow or change.
Create and read a tuple
point = (3, 4)
date = (2024, 7, 15)
print(date[0])
print(date[1:])
print(len(date))
Output:
2024
(7, 15)
3
Tuple indexing, negative indices, slicing and membership follow the same rules as lists. A tuple slice returns a tuple. You can loop through a tuple or use +, *, min, max, sum, count and index when its items suit the operation.
The comma creates a nonempty tuple. t = 3, 4 makes (3, 4) even without parentheses. A one-item tuple needs a trailing comma:
| Expression | Value and type |
|---|---|
(5) | Integer 5 |
(5,) | One-item tuple (5,) |
() | Empty tuple |
tuple([1, 2]) | Tuple (1, 2) |
tuple("ab") | Tuple ('a', 'b') |
list(t) converts a tuple's items into a changeable list.
Understand what cannot change
point[0] = 5 raises TypeError because a tuple does not support item assignment. Tuples have no append, remove or sort methods; point.append(5) raises AttributeError.
A name can still be rebound to a new tuple:
point = (3, 4)
point = (5,) + point[1:]
print(point)
Output is (5, 4). The expression makes a new tuple; it does not edit the old one.
A tuple can hold a mutable item
t = ([1, 2], "x")
t[0].append(3)
print(t)
Output:
([1, 2, 3], 'x')
The first position still holds the same list. That list's contents changed. t[0] = [9] would replace the object in the position and is forbidden. Immutability of the outer tuple does not freeze an inner list.
Match the structure to its job
Use (x, y) for a coordinate, (255, 128, 0) for an RGB color or ("Ana", 90) for a two-field record. Each position has a particular meaning. Use a list for all the class's scores or a cart's items, which may grow and be reordered. A list of tuples, such as [("Ana", 90), ("Ben", 85)], combines a changeable collection with fixed record positions.
A tuple of numbers or strings can serve as a dictionary key, as in {(0, 0): "origin"}. Keys must be hashable, meaning they support Python's stable key lookup rules. A list is not hashable, and a tuple containing a list is not hashable either.
Compare tuples
Comparison starts on the left and stops at the first unequal pair. (1, 2, 5) < (1, 3, 0) is True: the first values tie, and 2 is less than 3. This same rule orders a list of tuple records when no key function is supplied.
Key Takeaways
- A tuple has fixed item positions but may contain a mutable object.
- The comma makes a nonempty tuple;
(5,)has one item. - Tuple reading operations follow sequence rules.
- Rebinding a tuple name creates a different value without editing the old tuple.
- Tuples used as dictionary keys need hashable contents.
- Tuple comparison uses the first unequal pair of items.
4.2 Unpack records into names
Packing gathers values into a tuple. Unpacking assigns an iterable's items to names in order. Together they let code give clear names to the fields of a record and receive several results from one function.
Match names to values
record = "Ana", 34, "Lima"
name, age, city = record
print(name, age, city)
Output:
Ana 34 Lima
The first item becomes name, the second age and the third city. Unpacking also works on lists and strings: first, second = [10, 20] and a, b, c = "xyz" assign their items in order. user, domain = "ana@example.com".split("@") gives 'ana' and 'example.com' because the split produces two pieces.
Without a starred name, the counts must match exactly. x, y = (1, 2, 3) raises ValueError for too many values; x, y, z = (1, 2) raises ValueError for not enough. Python does not silently discard extra items.
Swap values safely
a = 1
b = 2
a, b = b, a
print(a, b)
Output is 2 1. Python evaluates the entire right side using the old values before assigning either name on the left. The two-statement attempt a = b followed by b = a loses the old value of a and makes both names 2.
Collect the remaining items
A starred name receives a list of the leftover values:
first, *rest = [5, 6, 7, 8]
print(first, rest)
*init, last = [5, 6, 7, 8]
print(init, last)
Output:
5 [6, 7, 8]
[5, 6, 7] 8
The star can also occur between unstarred names: first, *middle, last = (5, 6, 7, 8) gives middle the list [6, 7]. The collected object is always a list, even when unpacking a tuple. head, *rest = [5] leaves rest as []. There must be enough items for the unstarred names, and only one starred name is allowed in the same unpacking pattern.
Unpack during a loop
for name, score in [("Ana", 90), ("Ben", 85)]:
print(name, score)
Output:
Ana 90
Ben 85
The header unpacks each record as it arrives. This is also how for i, item in enumerate(values): and for a, b in zip(left, right): work: each iteration supplies a pair.
Return several results
def min_max(values):
return min(values), max(values)
low, high = min_max([7, 2, 9])
result = min_max([7, 2, 9])
print(low, high)
print(result)
Output:
2 9
(2, 9)
The function returns one tuple. The caller can unpack it or retain the whole object. An underscore conventionally names a value the code does not need: _, month, day = (2024, 7, 15) keeps the month and day under descriptive names. _ remains an ordinary variable, not a special discard operation.
Key Takeaways
- Packing collects values; unpacking assigns them in order.
- Unstarred names require an exact item count.
- A starred name receives a list of leftovers, possibly empty.
- Swap with
a, b = b, ato preserve both old values. - Multiple returned values are commonly packed into one tuple.
5Track sharing and make copies
Two names can refer to one list, and a copied outer list can still share its rows. These relationships explain why an edit sometimes appears in more than one place. Trace which object a name reaches before deciding whether an operation mutates that object or rebinds the name. The same reasoning applies when a function receives a list and when a default argument is reused across calls. Copying provides independence at the levels that need it.
5.1 Track names that share one list
A variable is a name that refers to an object. Assignment changes what a name refers to; it does not automatically copy the object. With a mutable list, two names can therefore observe the same changes.
Follow the references
a = [1, 2, 3]
b = a
b.append(4)
print(a)
print(b)
Output:
[1, 2, 3, 4]
[1, 2, 3, 4]
There is one list and two names for it. b is an alias of a. The append changes the shared object, so reading it through either name shows the added item. Draw two arrows, one from each name, to the same list when tracing this code.
Separate equality from identity
a = [1, 2]
b = a
c = [1, 2]
print(a == b, a == c)
print(a is b, a is c)
Output:
True True
True False
== compares contents; is tests whether the objects are the same object. c has equal contents but is a separate list. id(x) gives an object's identity number, so id(a) == id(b) agrees with a is b. Identity numbers do not tell you which items a list contains.
Use == when asking whether contents match. Use is when checking sharing or a special object such as None. A fresh list literal creates a separate list, so a is [1, 2] is false for an existing list a, even if its contents match.
Mutation and rebinding have different reach
| Statement | What changes? | What does an alias see? |
|---|---|---|
b.append(4) | Existing list | Added item |
b[0] = 9 | Existing list | Replaced item |
b = [7, 8] | The name b | Original list unchanged |
After the last statement, b points at a new list. a continues to refer to the original object. Rebinding one name does not redirect every name that once referred to that object.
Trace += and + separately
For lists, += extends the existing list:
a = [1]
b = a
a += [2]
print(a, b)
Output is [1, 2] [1, 2]. In contrast:
a = [1]
b = a
a = a + [2]
print(a, b)
Output is [1, 2] [1]. + creates a new list, and assignment makes a refer to it. b still refers to the original one-item list.
Look for less visible aliases
row = [0, 0] followed by table = [row, row] stores the same row twice. table[0][0] = 5 produces [[5, 0], [5, 0]] because both positions reach the same inner list.
Numbers and strings cannot change in place. After x = 5, y = x, x += 1, y stays 5; x has been rebound. A tuple's item positions also stay fixed, but an inner list can change. After t = ([1], 2), u = t and t[0].append(3), u shows ([1, 3], 2): both names still reach the same tuple and its same mutable list.
Key Takeaways
- Assignment shares a reference; it does not copy a list.
==compares values, whileischecks object identity.- Mutation is visible through aliases; rebinding redirects one name.
- For lists,
+=mutates while+creates a new list. - Sharing can occur inside a table or tuple as well as between variable names.
5.2 Copy the levels that need independence
Copying creates a new object, but the depth of that copy matters. A new outer list can still hold references to the original inner lists.
Make a new outer list
a = [1, 2, 3]
b = a.copy()
b.append(4)
print(a)
print(b)
print(a is b)
Output:
[1, 2, 3]
[1, 2, 3, 4]
False
a[:], list(a) and a.copy() all make a shallow copy of a list. Its outer container is new, and its item references are copied. With immutable numbers or strings, replacing or adding an item in one outer list leaves the other alone.
See what a shallow copy shares
a = [[1, 2], [3, 4]]
b = a.copy()
b[0].append(99)
print(a)
print(b is a, b[0] is a[0])
Output:
[[1, 2, 99], [3, 4]]
False True
The two outer lists differ, but their first items refer to the same inner list. append() changes that inner object.
Replacing a position in b is different. After b[1] = [0], b has a different second row while a[1] remains [3, 4]. Assignment changes one reference in b's outer list; it does not mutate the old second row.
Copy nested lists too
import copy
a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)
b[0].append(99)
print(a)
print(b)
Output:
[[1, 2], [3, 4]]
[[1, 2, 99], [3, 4]]
import copy makes the copying module available. copy.deepcopy() recursively copies the nested list structure, so edits to copied inner lists do not reach the original. Use it when changes at those inner levels must be independent. A shallow copy is enough if only the outer list's order or item references will change.
Avoid repeated references when building rows
table = [[0] * 3] * 2
table[0][0] = 7
print(table)
Output is [[7, 0, 0], [7, 0, 0]]. Multiplication repeated the reference to one row. It did not construct two rows.
Build each row inside the loop:
table = []
for r in range(2):
table.append([0] * 3)
table[0][0] = 7
print(table)
Output is [[7, 0, 0], [0, 0, 0]]. [0] * 3 itself is safe for independent counters: integers cannot be mutated, and item assignment replaces just one position.
Choose a copy for a reason
Preserving the original order before sorting requires a new outer list. Preserving original nested measurements while changing copied cells requires independent inner lists too. Read-only processing needs no copy, and intentional shared editing can use aliases. To investigate a nested bug, check both b is a and b[0] is a[0]; testing only the outer lists misses inner sharing.
Key Takeaways
- Slicing,
list()andcopy()make a new outer list. - A shallow copy retains references to the original items.
- Replacing a copied row differs from mutating a shared row.
copy.deepcopycopies nested lists recursively.- Nested list multiplication repeats references to one row.
- Copy only the levels whose changes need to be independent.
5.3 Make a function’s list effects clear
A function parameter is another name for the object supplied by the caller. A list argument is not automatically copied. The function can mutate that object, rebind its local parameter or return a new result; these actions affect the caller in different ways.
Mutation reaches the caller
def add_bonus(scores):
scores.append(5)
marks = [80]
result = add_bonus(marks)
print(marks)
print(result)
Output:
[80, 5]
None
scores and marks initially refer to the same list. Appending through scores changes it. Because the function has no explicit return statement, its result is None.
By contrast, def reset(scores): scores = [] rebinds only the local parameter. The caller's marks still refers to its old list. Use scores.clear() to empty that actual shared list.
Keep a returned list when needed
Two common designs are changing a list in place and returning None, or leaving it alone and returning a new list:
def drop_first(values):
del values[0]
def tail(values):
return values[1:]
For nums = [1, 2, 3], calling drop_first(nums) leaves nums as [2, 3]. Writing nums = drop_first(nums) would instead bind nums to None. Starting again from [1, 2, 3], shorter = tail(nums) gives shorter the list [2, 3] while nums stays unchanged. Calling tail(nums) without keeping its result discards the new list.
Other designs are useful too: sum() returns a summary, and pop() both changes a list and returns an item. Make the effect and return value clear in a function's name or docstring.
Build a result without changing the input
def without_negatives(values):
kept = []
for value in values:
if value >= 0:
kept.append(value)
return kept
original = [3, -2, 0, 7]
print(without_negatives(original))
print(original)
Output:
[3, 0, 7]
[3, -2, 0, 7]
A caller can also protect its outer list by passing a shallow copy, such as drop_first(original[:]). An operation that edits inner lists would need copying at those levels too.
Avoid a shared mutable default
def add_item(item, basket=[]):
basket.append(item)
return basket
The default list is created when the def statement runs, once. add_item("a") returns ['a'], and the next default call add_item("b") returns ['a', 'b']. Use None to request a fresh list:
def add_item(item, basket=None):
if basket is None:
basket = []
basket.append(item)
return basket
Each call without a basket now creates its own list. Passing an existing basket still allows intentional shared changes. A function cannot mutate a number or string, or replace a tuple's positions, but it can mutate a list stored in a tuple, such as by calling pair[0].append(9).
Key Takeaways
- A parameter initially refers to the caller’s object.
- Mutating a list parameter changes that object; rebinding the parameter does not.
- Keep a newly returned list if the program needs it.
- Check both a function’s effect and its return value.
- A mutable default list is shared across default calls.
- Use
Noneand create a list inside the function for a fresh default.
6Put sequences in order
Putting records in order requires two choices: which values decide the order, and whether the original collection should change. Python can sort a list in place or return a new list from any iterable. Key functions let a program compare one field, a computed value or several fields in sequence. Equal keys preserve their input order, which makes ties predictable and supports sorting by more than one rule.
6.1 Choose how to sort or reverse data
Sorting puts items in comparison order. Reversing flips their current order. Also decide whether the program should change the existing list or keep it and receive a new list.
Sort in place or keep a new list
nums = [3, 1, 2]
new = sorted(nums)
print(nums)
print(new)
nums.sort()
print(nums)
Output:
[3, 1, 2]
[1, 2, 3]
[1, 2, 3]
sorted() creates a new list. sort() is a list method that rearranges the existing list and returns None. nums = nums.sort() loses the name's reference to the list and binds it to None. Write nums.sort() on its own line or use nums = sorted(nums). print(nums.sort()) prints None even though the list has been reordered.
sorted() accepts any iterable and always returns a list. sorted((3, 1, 2)) gives [1, 2, 3], and sorted("cab") gives ['a', 'b', 'c']. Strings and tuples have no in-place sort() method.
Descending order and reversed order
Expression for nums = [3, 1, 2] | Result | Changes nums? |
|---|---|---|
sorted(nums, reverse=True) | [3, 2, 1] | No |
nums.sort(reverse=True) | Returns None; list becomes [3, 2, 1] | Yes |
nums[::-1] | [2, 1, 3] | No |
list(reversed(nums)) | [2, 1, 3] | No |
nums.reverse() | Returns None; list becomes [2, 1, 3] | Yes |
Each row starts from the original list. reverse=True requests descending comparison order and must be given by name; sorted(nums, True) raises TypeError. Reversing simply visits the existing positions backward, so it does not necessarily produce descending values.
Check the values being compared
Numbers sort by numerical value, including mixed integers and floats: sorted([2.5, -1, 2]) gives [-1, 2, 2.5].
Text is compared character by character. sorted(["10", "9", "100"]) gives ['10', '100', '9']. The first character '1' sorts before '9', and a string prefix comes before a longer string beginning with it. Convert numeric strings with int() or float() when numerical ordering is wanted.
The capital letters A–Z sort before the lowercase letters a–z. sorted(["b", "B", "a"]) gives ['B', 'a', 'b']. Default string order is based on character codes; it is not a case-insensitive dictionary order.
All items compared must support < with one another. sorted([3, "two", 1]) raises TypeError. Clean or convert the data before sorting.
Use sorted positions
For an odd number of scores, sorting makes the middle value easy to read:
scores = [72, 95, 64, 88, 79]
ordered = sorted(scores)
median = ordered[len(ordered) // 2]
print(ordered)
print(median)
Output is [64, 72, 79, 88, 95] followed by 79. The original list still records the order the scores arrived. This single-middle-item calculation applies to odd-length nonempty lists.
Key Takeaways
sortmutates a list and returnsNone;sortedreturns a new list.sortedaccepts iterables such as tuples and strings.reverse=Truesorts descending; reversing alone flips current positions.- Numeric strings use text order unless converted.
- Items must support comparison with one another.
6.2 Sort records by the fields that matter
A key function computes the comparison value for each item. The original items remain intact in the sorted result. This lets a program sort text by length or records by a selected field.
Pass a function, not a function call
words = ["kiwi", "fig", "banana"]
print(sorted(words, key=len))
Output:
['fig', 'kiwi', 'banana']
Python calls len once for each item and compares the resulting lengths, 4, 3 and 6. Pass key=len, without parentheses. key=len() tries to call len immediately with no argument and fails.
For lowercase comparison, use key=str.lower. With ["banana", "apple", "Cherry"], the default order is ['Cherry', 'apple', 'banana']. With key=str.lower, the result is ['apple', 'banana', 'Cherry']. The original capital C remains in the result; only the comparison keys are lowercase.
Select a record field
results = [("Ana", 90), ("Ben", 72), ("Cy", 85)]
def by_score(record):
return record[1]
print(sorted(results, key=by_score))
Output:
[('Ben', 72), ('Cy', 85), ('Ana', 90)]
The function receives one record at a time. record[1] selects its score. Add reverse=True to put the highest score first. results.sort(key=by_score, reverse=True) uses the same rule but changes results itself.
key=by_score(results) is different: it calls the function on the whole list and passes its result as the key argument. Here that result is the tuple ('Ben', 72), which cannot be called as a function, so sorting raises TypeError.
Use several fields
Without a key, tuples compare their first items, then their second items to break first-item ties. Sorting [("Ben", 72), ("Ana", 90), ("Ana", 85)] gives [('Ana', 85), ('Ana', 90), ('Ben', 72)].
A key can return a tuple to choose a different field order:
def rank_key(record):
return (-record[1], record[0])
results = [("Dee", 85), ("Ana", 90), ("Cy", 85)]
print(sorted(results, key=rank_key))
Output:
[('Ana', 90), ('Cy', 85), ('Dee', 85)]
Negating the score makes larger scores have smaller keys. Names then break score ties in ascending order. reverse=True on a positive (score, name) key would reverse both fields, including the names, so it would not meet this mixed-direction rule.
Keep equal-key items in order
Python's sorting is stable: items with equal keys keep their input order. Sorting ["bb", "a", "cc", "d"] by len gives ['a', 'd', 'bb', 'cc']. The tie between the two one-letter words keeps 'a' first; the two-letter tie keeps 'bb' first. Stability also permits sorting by a secondary field first, then by the main field.
min() and max() accept key functions too. max(words, key=len) returns 'banana', not its length. When keys tie, these functions return the first matching item encountered.
Key Takeaways
- A key function maps one item to its comparison value.
- Pass the function itself, such as
key=lenorkey=by_score. - Key results control ordering without replacing the original items.
- A tuple key orders by its first field, then uses later fields to break ties.
- Negating a numeric key can reverse just that field’s direction.
- Stable sorting preserves input order among equal keys.
minandmaxreturn original items and choose the first on a key tie.
Python Lists and Tuples examples
1Read a week of delivery counts
13 steps
- 1IntroductionKeep the counts in order
A delivery log stores one count per day. A list keeps the order, so a position identifies a day and a slice selects several days. You can then calculate a total or average from the selected values.
Work with
deliveries = [12, 7, 15, 9, 17]. These are five daily counts in arrival order. First track the positions, then the slice boundaries, and finally the type of result each operation produces. - 2ExampleMatch counts to positions
The five counts occupy indices 0 through 4:
deliveries = [12, 7, 15, 9, 17] print(deliveries[0], deliveries[4])Output is
12 17.len(deliveries)is 5, but index 5 does not exist. A count tells you how many positions are present; it does not name the last one. The final count can also be read asdeliveries[-1], using a negative index from the end. - 3TipCheck a reading before using it
Membership answers a different question from indexing:
print(9 in deliveries) print(4 in deliveries)Output is
TruethenFalse. The value 9 occurs, but 4 does not, even though 4 is a valid index.inchecks the stored values. If you want the count at position 4, usedeliveries[4], which returns17. - 4ChallengeFind the second-to-last count
What does
deliveries[-2]return, and woulddeliveries[len(deliveries)]work?---reveal---
The negative index
-2selects9, one place before the final item17. The second expression tries index 5 and raises IndexError. Uselen(deliveries) - 1or-1to select the last item; the number of items is one past the final nonnegative index. - 5ExampleSelect the middle three days
Use index 1 as the start and index 4 as the excluded stop:
middle = deliveries[1:4] print(middle)Output is
[7, 15, 9]. Read the selected positions as 1, 2 and 3. Position 4 contains 17, but it marks the stopping boundary here.middleis a new list, so changing its outer positions will not replace a position indeliveries. - 6ExplanationLeave out a boundary
deliveries[:2]gives[12, 7], the first two days.deliveries[2:]gives[15, 9, 17], all remaining days. Both slices meet at boundary 2, so joining them rebuilds the original contents.deliveries[-2:]gives[9, 17]. A negative bound counts from the end.deliveries[20:]is[]: an out-of-range slice boundary is clipped, unlike an out-of-range item lookup. - 7ExampleStep through alternate days
A third slice field controls spacing:
print(deliveries[::2]) print(deliveries[::-1])Output is
[12, 15, 17]then[17, 9, 15, 7, 12]. Step 2 visits indices 0, 2 and 4. Step -1 visits every item backward. Both results are new lists. A zero step cannot advance and raises ValueError. - 8ChallengeDistinguish a count from a list
What are the values and types of
deliveries[2]anddeliveries[2:3]?---reveal---
deliveries[2]is the integer15.deliveries[2:3]is the list[15]. The slice selects one position but still returns a list. This difference matters if the next operation expects a numeric count: adding 1 to the integer works, while adding 1 directly to the list raises TypeError. - 9ExampleCalculate an average from the slice
The middle slice is
[7, 15, 9]. Add its items and divide by its length:total = sum(middle) mean = total / len(middle) print(total) print(mean)Output is
31then10.333333333333334. The total is 7 + 15 + 9, and the divisor is 3./produces a floating-point result, so this average is displayed with a decimal approximation. - 10Key InsightHandle a selection with no days
A slice may be empty, so an average needs a guard:
selected = deliveries[20:] if selected: print(sum(selected) / len(selected)) else: print("No days selected")This prints
No days selected. Empty lists count as false. Althoughsum([])is 0, dividing that total bylen([])would divide by zero.minandmaxalso fail on these empty inputs. - 11ConnectionBuild a display line
A display needs strings, not a list of integers:
pieces = [] for count in deliveries: pieces.append(str(count)) print(", ".join(pieces))Output is
12, 7, 15, 9, 17.joinis called on the separator and places it between items. Passing the numeric list directly would fail because every joined item must be a string.splitgoes the other way, dividing text into string pieces. - 12ChallengeSelect, total and keep the original
What does this code print?
selected = deliveries[-3:] selected[0] = 0 print(sum(selected), deliveries[2])---reveal---
It prints
26 15. The slice begins as[15, 9, 17], then its first position is replaced, making[0, 9, 17]. Those values total 26. The outer slice is separate, so the original count atdeliveries[2]stays 15. - 13RecapChoose the result you need
Read one position for a single count, use a slice for a sequence, and use summary functions for totals or extremes. A list slice creates a new outer list.
Before averaging a selection, handle its empty case. When building display text, convert numeric values to strings before joining them.
2Edit a supply request
10 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionFollow the list and the returned value
- 2ExampleAdd a batch of items
- 3ExamplePut one item at the front
- 4ExampleRemove and save a collected item
- 5ChallengeChoose a removal by value
- 6ExampleFind a correction’s position
- 7ExampleReplace one item with a batch
- 8ChallengeDelete a range and find a value
- 9ChallengeFinish the request without losing it
- 10RecapMatch the change to the operation
3Clean readings and total a table
13 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionDecide what each loop carries
- 2ExplanationRead a value without editing its position
- 3ExampleReplace invalid readings by index
- 4ConnectionPair labels with readings
- 5ChallengeExplain a skipped item
- 6ExampleCount the positive readings
- 7ExampleBuild a filtered and transformed result
- 8TipSearch until the first match
- 9ChallengeChoose a valid maximum
- 10ExampleSelect a row and a cell
- 11ExampleTotal all rows
- 12ChallengeFilter across the whole table
- 13RecapKeep setup separate from repeated work
4Use a fixed record and unpack its fields
10 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionKeep a record together
- 2ExampleCreate the station record
- 3Key InsightTest the immutability boundary
- 4ChallengeMake a one-item tuple
- 5ExampleGive each field a name
- 6ExampleKeep the first reading and the rest
- 7ChallengeSwap coordinate values
- 8ExampleReturn a pair of extremes
- 9ChallengeRead and unpack one selected field
- 10RecapRead structure before unpacking
5Trace a copied table through a function
14 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionDraw paths to objects
- 2ExampleCreate an alias
- 3ExampleRedirect one name
- 4ChallengePredict two kinds of addition
- 5ExampleCopy the outer table
- 6ExampleMutate a shared row
- 7Key InsightReplace a copied row
- 8ChallengeChoose a deeper copy
- 9ExampleMutate through a parameter
- 10ConnectionReturn a separate list
- 11ExplanationAvoid a persistent default basket
- 12ChallengeSeparate local rebinding from clearing
- 13ChallengeTrace a shallow copy passed to a function
- 14RecapTrace the level being changed
6Rank records without losing their arrival order
13 steps
Save this lesson to follow every Walkthrough step by step.
- 1IntroductionSeparate stored data from comparison keys
- 2ExampleKeep the arrival order
- 3ExampleCompare reversal with descending sorting
- 4TipCheck the input type
- 5ChallengeFollow a sort result
- 6ExampleChoose a score key
- 7Key InsightKeep tied records in arrival order
- 8ChallengePass a callable
- 9ExampleAdd an alphabetical tie-breaker
- 10TipReverse only the numeric direction
- 11ConnectionPick an item by an extreme key
- 12ChallengeKeep records and names in their own forms
- 13RecapChoose the effect and the rule
Python Lists and Tuples practice questions
Set 1: Process values, positions and tables10 Practice Questions
Question 1 of 10
What list does this code print?
values = [8, 3]
for value in values:
value = 0
print(values)
Show answerHide answer
value is rebound to 0 on each pass, but no list position is assigned a new value. The original list therefore stays [8, 3]. To produce [0, 0], the loop would need to assign to each list index, such as values[i] = 0.Question 2 of 10
What value does this code print?
count = 0
for size in [10, 7, 10, 13, 6]:
if size >= 10:
count += 1
print(count)
Show answerHide answer
> 10, excluding the boundary values; a total of 33 would add the matching sizes instead of counting them.Question 3 of 10
table = [[6, 8, 10], [11, 13, 15]], what does table[1][0] + table[0][2] produce?Show answerHide answer
11. The second selects row 0 and then its third item, 10, so the total is 21. Using 13 for the first term would take column 1 instead of column 0, mixing the two index roles.Question 4 of 10
list(zip(["Lee", "Mo", "Nia"], [41, 56])) contain?Show answerHide answer
zip forms pairs at matching positions and stops when either input ends. There are two scores, so only two name–score pairs can be formed. It does not create a third pair with a missing score, and it does not combine every name with every score.Question 5 of 10
What is printed?
values = [7, -4, -8, 2]
position = -1
for i, value in enumerate(values):
if value < 0:
position = i
break
print(position, values[position])
Show answerHide answer
-4 and succeeds. The code stores 1 and breaks, so the final lookup retrieves values[1], which is -4. Reporting 2 -8 would continue searching and keep the last negative, but break prevents that later update.Question 6 of 10
How many times does total += value run?
total = 0
for row in [[2, 4], [6], [8, 10, 12]]:
for value in row:
total += value
Show answerHide answer
Question 7 of 10
What list remains after this code?
values = [0, 0, 1, 0]
for value in values:
if value == 0:
values.remove(value)
Show answerHide answer
remove(0) deletes the first remaining zero, leaving [1, 0]. Removing every zero safely requires a copy or a new retained-items list.Question 8 of 10
[-14, -6, -19]. What should initialize its running maximum?Show answerHide answer
-6 when that larger value is visited. Starting at 0 would keep 0 throughout, wrongly reporting a value greater than every reading but absent from the list.Question 9 of 10
What does this code print?
kept = []
for text in ["4", "15", "8", "21"]:
number = int(text)
if number % 2 == 0:
kept.append(number + 1)
print(kept)
Show answerHide answer
[5, 9]. [4, 8] would filter correctly but omit the transformation; transforming every input would ignore the condition.Question 10 of 10
What table results?
table = []
for r in range(2):
table.append([0] * 2)
table[1][0] = 6
Show answerHide answer
[[0, 0], [6, 0]]. Both first cells would change if the outer list repeated one shared row reference, but this construction creates a new row each time.Set 2: Read, slice and change sequences10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
levels = [14, 29, 37, 52], what is levels[-2]?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
codes = [2, 5, 8, 11, 14, 17], what is codes[1:5:2]?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
What list results from this code?
items = ["pen"]
items.append(["clip", "pad"])
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What does this code print?
parts = "6|12|18".split("|")
print(len(parts), parts[1])
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What is len(values) after this code?
values = [4, 7, 10, 13]
values[1:3] = [20, 21, 22]
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does this code print?
queue = [18, 0, 24]
removed = queue.pop(0)
print(removed, queue)
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What does this code print?
a = [3, 6, 9, 12, 15]
b = a[-4:-1]
print(b[::-1][1])
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
items = [9, 16, 25], what happens when Python evaluates items[len(items)]?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
[4, 99] < [5, 1]?Show answerHide answer
Save this lesson to see this answer.
Set 3: Unpack records and trace shared objects10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
label, amount = ("rice", 4), what value does amount hold?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
middle after first, *middle, last = (2, 5, 8, 11, 14)?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
What does this code print?
a = [5, 8]
b = [5, 8]
print(a == b, a is b)
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What does this code print?
record = ([2], "ready")
other = record
record[0].append(7)
print(other)
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What does this code print?
a = [4]
b = a
a += [9]
a = a + [12]
print(a, b)
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
What does this code print?
def bounds(values):
return min(values), max(values)
low, high = bounds([18, 5, 12])
low, high = high, low
print(low, high)
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does this code print?
a = [2, 6]
b = a.copy()
b[0] = 10
print(a, b)
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What does this code print?
a = [[4], [8]]
b = a.copy()
b[0].append(6)
b[1] = [9]
print(a)
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
What does this code print?
row = [1, 2]
table = [row, row]
row = [8, 9]
table[0][1] = 7
print(table, row)
Show answerHide answer
Save this lesson to see this answer.
Set 4: Control changes across function calls10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
What does this code print?
def change(values):
values.append(8)
values = [0]
return values
original = [3]
result = change(original)
print(original, result)
Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
What table results?
table = [[0] * 2] * 3
table[2][1] = 4
table[0] = [9, 9]
Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
codes = ["q", "r", "q", "s", "q"], what is codes.index("q", 1)?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
tags = ["new", "old", "new"], what does tags.count("done") return?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What does this code print?
def reset(values):
values = []
values = [11, 22]
reset(values)
print(values)
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
What does this code print?
import copy
a = [[3], [7]]
b = copy.deepcopy(a)
b[0].append(5)
print(a, b[0] is a[0])
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does the final line print?
def collect(item, items=[]):
items.append(item)
return items
first = collect("x")
second = collect("y")
print(first is second, first)
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What does this code print?
def trim(values):
del values[0]
items = [6, 9, 12]
result = trim(items)
print(items, result)
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What is printed?
def add(item, values=None):
if values is None:
values = []
values.append(item)
return values
a = add(4)
b = add(7)
c = add(9, a)
print(a, b, c is a)
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
What does this code print?
def edit(rows):
rows[0].append(5)
rows.append([9])
original = [[1], [2]]
edit(original[:])
print(original)
Show answerHide answer
Save this lesson to see this answer.
Set 5: Choose sorting rules and resolve ties10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
result hold after nums = [8, 2, 5] and result = nums.sort()?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
sorted(["20", "3", "11"]) return?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
sorted(["pear", "a", "plum", "to"], key=len) return?Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
values = [6, 1, 4], what pair of results comes from values[::-1] and sorted(values, reverse=True), in that order?Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
(name, score) pairs. What key function body ranks higher scores first and names A to Z when scores tie?Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
What order does this code produce?
records = [("Zoe", 8), ("Ali", 8), ("Mia", 6)]
def by_score(record):
return record[1]
print(sorted(records, key=by_score, reverse=True))
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does this code print?
words = ["oak", "elm", "pine", "ash"]
print(max(words, key=len), min(words, key=len))
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What does this code print?
words = ["beta", "Alpha", "alpha", "Beta"]
print(sorted(words, key=str.lower))
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
What does this code print?
a = [9, 4, 7]
b = a
c = sorted(a)
a.reverse()
print(b, c)
Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
(name, score) records by name A to Z. It then stably sorts them by score, high to low. How are equal-score records ordered in the final list?Show answerHide answer
Save this lesson to see this answer.
Set 6: Debug and combine sequence operations10 Practice Questions
Save this lesson to see every answer and practice every set.
Question 1 of 10
values = [12, 24], what is values[5:20]?Show answerHide answer
Save this lesson to see this answer.
Question 2 of 10
None otherwise?Show answerHide answer
Save this lesson to see this answer.
Question 3 of 10
What does this code print?
items = [1, 2]
result = items.extend([3, 4])
print(len(items), result)
Show answerHide answer
Save this lesson to see this answer.
Question 4 of 10
What does this code print?
records = [("A", 4), ("B", 9)]
amounts = []
for _, amount in records:
amounts.append(amount)
first, *rest = amounts[::-1]
print(first, rest)
Show answerHide answer
Save this lesson to see this answer.
Question 5 of 10
What does this code print?
values = [5, -2, 8, -4]
for i, value in enumerate(values):
if value < 0:
values[i] = -value
print(values[1::2])
Show answerHide answer
Save this lesson to see this answer.
Question 6 of 10
What does this code print?
a = [[9, 2], [8, 1]]
b = a[:]
b.reverse()
b[0][0] = 6
print(a)
Show answerHide answer
Save this lesson to see this answer.
Question 7 of 10
What does this code print?
records = [("Rae", 7), ("Dev", 9), ("Cam", 7)]
def rank(record):
return (-record[1], record[0])
ordered = sorted(records, key=rank)
name, score = ordered[1]
print(name, score)
Show answerHide answer
Save this lesson to see this answer.
Question 8 of 10
What does this code print?
def select(values):
kept = []
for value in values:
if value >= 5:
kept.append(value * 2)
return kept
a = [3, 5, 8]
b = select(a)
b.pop(0)
print(a, b)
Show answerHide answer
Save this lesson to see this answer.
Question 9 of 10
[31, 12, 27, 18, 24, 15, 21]. After sorting a copy, what is the middle value?Show answerHide answer
Save this lesson to see this answer.
Question 10 of 10
What does this code print?
point = (6, 8)
old = point
point = (10,) + point[1:]
print(old, point)
Show answerHide answer
Save this lesson to see this answer.
Stuck on your own question? Homework Help
Key Terms
A
Accumulator
total = 0 before processing readings, then use total += reading to retain earlier additions.Alias
current = queue, appending through current also changes the list reached through queue.append()
append() list method adds its argument as one item at the end of the existing list and returns None.[3, 4] to [1, 2] produces [1, 2, [3, 4]], because the argument stays one item.C
Case-insensitive key
key=str.lower lets "Oak" and "oak" compare equally without changing their capital letters.Cell
grid[0][2] = 9 replaces the first row’s third cell, assuming that position already exists.Concatenation
+ creates a new outer list from two lists.morning + afternoon can combine two lists of readings while leaving each original list intact.count()
count() list method returns the number of items equal to its argument and returns 0 when the value is absent.[2, 2.0, 5].count(2) is 2 because both the integer 2 and the float 2.0 compare equal to 2.Counter
D
Deep copy
copy.deepcopy(rows) can preserve original table cells while a separate nested structure is edited.Descending order
reverse=True.[5, 1, 8] gives [8, 5, 1]; reversing its positions alone gives [8, 1, 5].E
enumerate()
enumerate() built-in supplies pairs containing a running number and an item, beginning with number 0 by default.for i, value in enumerate(values): gives code both an index and its corresponding current item.extend()
extend() list method adds each item from an iterable to the end of the existing list and returns None.[1, 2] with [3, 4] produces four outer items; extending with "ab" adds two characters.F
Filtering
First-match search
break to finish the search immediately.H
Hashable value
(5, 9) can be a coordinate key, but ([5], 9) cannot because its inner list is unhashable.I
Identity
is; equal contents can belong to different list objects.[1, 3] literals compare equal, but an identity check between those lists is false.Immutability
In-place operation
values.clear() empties the existing list, so every alias sees that list become empty.Index
colors = ["blue", "gold"], index 1 selects 'gold', which is also the item at index -1.index()
index() list method finds the first equal item in its search range and returns that item’s index in the whole list.labels.index("go", 2) begins searching at position 2 but still counts its answer from position 0.insert()
insert() list method adds an item before a specified position, shifting later items and increasing the list’s length.queue.insert(0, "urgent") places a new item at the front without overwriting the previous first item.Item
["desk", ["pen", "pad"]], the outer list has two items, even though the inner list contains two strings.Item assignment
prices[1] = 6.5 corrects one recorded price; it cannot create an item at index len(prices).Iterable
list().list(range(3)) collects them into the new list [0, 1, 2].Iteration
for loop visiting a list from its first item to its last.names assigns each current name to the loop variable before running its body.J
join()
join() string method combines supplied strings into one string, placing the string it is called on between items." / ".join(["red", "blue"]) makes 'red / blue'; numeric items must first be converted to strings.K
Key function
key=len orders words by length without replacing those words with their length numbers.L
Lexicographic order
[3, 20] < [4, 1] is true because the first items decide the order before the second items are compared.List
scores = [73, 91, 73] and process them together.List parameter
values.clear() empties the caller’s list; assigning values = [] does not.Loop variable
for value in values: value = 0, the loop name changes but the stored list positions do not.M
Mean
[6, 10, 14], sum(readings) / len(readings) computes the mean as 10.0.Median
len(ordered) // 2.[5, 12, 2] gives [2, 5, 12], placing the median 5 at the middle index 1.Membership test
in or not in."ready" in statuses can decide whether a list contains that exact, case-sensitive status string.Method
queue.append("next") calls the list’s method and supplies the item to add as its argument.Mutable default argument
basket=[] keeps appended items between default calls because each call reaches the same list.Mutation
items[0] = 7 mutates the list; any alias to that list sees its first position become 7.N
Nested list
[[2, 5], [7]], the outer list contains two rows whose lengths are two and one.Nested loop
None default
None default can mark an omitted list argument so a function creates a fresh list inside its body for each default call.values=None, the branch if values is None: values = [] avoids an accidentally shared default list.O
Omitted bound
values[::-1], omitted bounds let the backward slice include the whole list in reversed order.One-item tuple
(11,) is a tuple, whereas (11) evaluates to the integer 11 without making a collection.Outer list
b[0] = [9] replaces a row reference, while b[0].append(9) changes the existing row object.P
Packing
result = lowest, highest stores both values in a tuple that can be returned from a function.pop()
pop() list method removes and returns an item by index, using the last position when no index is supplied.current = queue.pop(0) saves the first queued item and removes that position from the existing list.R
Rebinding
b = a, assigning b = [] gives b a new list while a continues to refer to the original.Record
("Kai", 86) can represent a name and score; a list of such records can grow as results arrive.Reference
b = a gives both variable names a path to the same list, so edits can be shared.remove()
remove() list method deletes the first item equal to its argument and raises ValueError when no match exists.labels.remove("old") deletes one matching value; it does not interpret "old" as a position.Repetition
* with an integer to repeat a sequence’s item references in order, producing an empty sequence for nonpositive counts.[0] * 5 creates five counter positions, while repeating a row list can create shared inner rows.Return value
None when its body has no explicit return statement.Reversal
values.reverse() mutates a list, while values[::-1] creates a reversed shallow copy.reversed()
reversed() built-in supplies sequence items from last to first without rearranging the sequence’s stored positions.for task in reversed(tasks): processes the last task first while keeping the original list order.Row
grid[1] retrieves the entire second row, so len(grid[1]) counts that row’s cells.Running maximum
S
Shallow copy
b = a.copy(), appending to b changes its outer list, but editing a shared row can affect a too.Shared row
table = [row, row] stores one row twice, even though printing the table displays two row positions.Simultaneous swap
left, right = right, left preserves both values without requiring a separately named temporary value.Slice
tasks[1:4] makes a list from positions 1, 2 and 3 without including the item at position 4.Slice assignment
values[1:2] = [8, 9] replaces one position with two values, increasing the list’s length by one.Slice step
values[1::2] selects every second position starting at 1; a negative step moves backward.sort()
sort() list method rearranges the existing list by comparison order and returns None, with optional key and reverse arguments.scores.sort() changes the recorded order directly, and aliases to scores see the sorted positions.sorted()
sorted() built-in accepts an iterable and returns a new list of its items in comparison order, leaving the input order unchanged.ordered = sorted(scores) keeps the original arrival order available through the scores variable.split()
split() string method divides text into a list of string pieces using a specified separator or whitespace rules."yes|no|maybe".split("|") creates three separate text items from the separator-delimited input.Stable sorting
len.Starred name
first, *rest = (4, 8, 12), rest is [8, 12], even though the input is a tuple.Stop boundary
values[2:5], index 5 marks where selection stops and does not contribute an item.T
Tie-breaker
Transformation
int(text) for each numeric string builds a list that can be totaled with sum().Tuple
location = (5, 9) stores a fixed coordinate pair, which still supports indexing and slicing.Tuple key
(-score, name) ranks scores high to low and uses names A to Z to break score ties.U
Unpacking
name, score = ("Kai", 86) gives each record field a separate, meaningful variable name.Z
zip()
zip() built-in pairs corresponding items from input iterables and, by default, stops when the shortest input ends.About this lesson
Make your own Study Materials
Turn your notes, slides and documents into Study Guides, Practice Questions, Flashcards and 6 more tools.