Learning Goals
3 minBy the end of this lesson you can:
- Change one item in a list by assigning to its index.
- Replace a whole slice with a different number of items.
- Copy a list properly, and explain what goes wrong when you do not.
Warm-Up · Text Will Not, Lists Will
5 minTwo attempts to change the first item. One of them fails. Which, and why?
word = "cat" word[0] = "b" names = ["cat", "dog"] names[0] = "bat"
Answer
Output
Traceback (most recent call last): TypeError: 'str' object does not support item assignment
The string line fails immediately; the list line would have worked fine. Strings are immutable, lists are mutable. That single difference explains most of how the two behave.
A string method hands you a new string. A list assignment edits the list you already have — no copy, no new name needed. Everything in this lesson follows from that.
New Concept · Editing Where It Stands
12 minA whiteboard, not a printed page. You rub out one word and write another; it is the same board, and everyone looking at it sees the change.
menu = ["pizza", "noodles", "pancake"] menu[1] = "fried rice" print(menu)
Output
['pizza', 'fried rice', 'pancake']
No new variable, no reassignment of menu — the list itself changed. Note you can only assign to a position that already exists; menu[9] = "x" raises IndexError. Growing a list is lesson 3.
Assigning to a slice
Put a slice on the left of the = and you replace that whole run at once.
scores = [10, 20, 30, 40, 50] scores[1:3] = [99, 98] print(scores) scores[0:2] = [1] print(scores) scores[1:1] = [7, 8] print(scores)
Output
[10, 99, 98, 40, 50] [1, 98, 40, 50] [1, 7, 8, 98, 40, 50]
- Same size — a straight swap of two items for two.
- Fewer — two items become one, and the list gets shorter.
- An empty slice
[1:1]selects nothing, so the new items are inserted at that point without removing anything.
scores[1:3] = 99 raises TypeError: can only assign an iterable. And scores[1:3] = "hi" does something surprising — a string is iterable, so you get 'h' and 'i' as two separate items. Wrap single values in brackets.
Two names, one list
This is the trap, and it catches everyone once.
original = ["Mia", "Leo"] backup = original backup[0] = "CHANGED" print("backup: ", backup) print("original:", original)
Output
backup: ['CHANGED', 'Leo'] original: ['CHANGED', 'Leo']
backup = original did not copy anything. It gave the same list a second name — like writing another label on the same box. Editing through one name changes what the other sees.
original = ["Mia", "Leo"] backup = original[:] backup[0] = "CHANGED" print("backup: ", backup) print("original:", original)
Output
backup: ['CHANGED', 'Leo'] original: ['Mia', 'Leo']
original[:] is a slice of everything, and a slice always builds a new list. list(original) and original.copy() do the same job.
Why it matters. Any program that edits data needs to change items in place, and any program that keeps an "before" copy needs a real one. Both are one line — and one of them is silently wrong if you get it out of order.
Worked Example · Editing a Timetable
12 minOne school day, changed three times, with a real copy kept so the changes can be shown.
# timetable.py - edit a day in place, keep a true copy of the original monday = ["Spanish", "Mathematics", "Science", "Rehat", "Sejarah", "PJK"] original = monday[:] print("Before:") for i in range(len(monday)): print(" ", i, "-", monday[i]) # 1. One swap: PJK is cancelled, Coding Club instead monday[5] = "Coding Club" # 2. A double period: Science becomes two slots of Physics monday[2:3] = ["Physics", "Physics Lab"] # 3. An assembly inserted at the very start, removing nothing monday[0:0] = ["Perhimpunan"] print() print("After:") for i in range(len(monday)): print(" ", i, "-", monday[i]) print() print("Periods before:", len(original)) print("Periods after: ", len(monday)) print("Original untouched:", original[5])
Output
Before: 0 - Spanish 1 - Mathematics 2 - Science 3 - Rehat 4 - Sejarah 5 - PJK After: 0 - Perhimpunan 1 - Spanish 2 - Mathematics 3 - Physics 4 - Physics Lab 5 - Rehat 6 - Sejarah 7 - Coding Club Periods before: 6 Periods after: 8 Original untouched: PJK
Three different edits, three different tools:
- Index assignment when one item becomes one other item.
- Slice assignment when one becomes two — the list grows by itself.
- Empty slice
[0:0]to insert at the front without deleting.
The assembly was inserted last on purpose. Insert it first and every index afterwards shifts by one, so monday[5] would no longer be PJK. When several edits use fixed indexes, do the ones that change the length at the end.
Try It Yourself
13 minStart with shopping = ["beras", "gula", "minyak", "telur"]. Change "gula" to "gula merah", then print the list before and after — using a real copy so both are visible.
Hint
shopping = ["beras", "gula", "minyak", "telur"] before = shopping[:] shopping[1] = "gula merah" print("Before:", before) print("After: ", shopping)
Start with plan = ["warm up", "main activity", "cool down"].
- Replace
"main activity"with three items:"drills","match","review"— using one slice assignment. - Insert
"register"at the very front without removing anything. - Print the length before and after, and one sentence explaining why it changed by 3 and not by 4.
Mini-Challenge 🔥 · Debug: The Backup That Was Not a Backup
8 minElla edits a team list and keeps a backup so she can show the change. Both lists come out identical, and one line crashes. Find two mistakes.
# team.py - buggy
team = ["Mia", "Leo", "Ana"]
backup = team
team[1] = "Theo"
team[3] = "Hugo"
print("Backup:", backup)
print("Team: ", team)Answer
backup = teamis not a copy. Both names point at one list, sobackupshows every edit. It must bebackup = team[:]— orteam.copy(), orlist(team).team[3]does not exist. The list has three items, indexes 0 to 2, so assigning to index 3 raisesIndexError: list assignment index out of range. Index assignment can only replace, never extend — adding is lesson 3, or a slice assignmentteam[3:3] = ["Hugo"]here.
The working version:
# team.py - fixed team = ["Mia", "Leo", "Ana"] backup = team[:] team[1] = "Theo" team[3:3] = ["Hugo"] print("Backup:", backup) print("Team: ", team)
Output
Backup: ['Mia', 'Leo', 'Ana'] Team: ['Mia', 'Theo', 'Ana', 'Hugo']
The first bug is the dangerous one: no error, no warning, and the backup you were relying on was never separate.
Recap
3 minLists are mutable, so items[i] = value edits in place. Assigning to a slice replaces that run, and the replacement may be a different length — an empty slice inserts without removing. b = a gives one list two names; b = a[:] makes a real copy.
Vocabulary Card
- mutable
- Can be changed in place. Lists are; strings are not.
- slice assignment
- Replacing a run of items, possibly with a different number of items.
- alias
- A second name for the same list — edits through one are seen by the other.
- shallow copy
- A new list holding the same items, made with
a[:]ora.copy().
Homework
4 minWrite seating_plan.py. Start with a list of eight classmates in seat order.
- Keep a true copy of the original before you change anything.
- Swap two pupils who sit apart, using two index assignments and a temporary variable.
- Replace the last two seats with three new pupils, using one slice assignment.
- Insert a pupil at the very front without removing anyone.
- Print the original and the final plan side by side, numbered, plus both lengths.
Hint for the swap: temp = seats[2], then move the other, then put temp back.
Sample · seating_plan.py
# seating_plan.py - four kinds of edit, with a real before-and-after seats = ["Mia", "Leo", "Ana", "Hugo", "Ella", "Theo", "Zoe", "Nia"] original = seats[:] # Swap seat 2 and seat 6 temp = seats[2] seats[2] = seats[6] seats[6] = temp # The last two seats become three pupils seats[-2:] = ["Zara", "Marco", "Ruby"] # A new pupil at the front, removing nobody seats[0:0] = ["Jonas"] print(f"{'Seat':<6}{'Original':<12}{'Final':<12}") print("-" * 30) rows = max(len(original), len(seats)) for i in range(rows): was = original[i] if i < len(original) else "" now = seats[i] if i < len(seats) else "" print(f"{i:<6}{was:<12}{now:<12}") print("-" * 30) print("Original seats:", len(original)) print("Final seats: ", len(seats))
Output
Seat Original Final ------------------------------ 0 Mia Jonas 1 Leo Mia 2 Ana Leo 3 Hugo Zoe 4 Ella Hugo 5 Theo Ella 6 Zoe Ana 7 Nia Zara 8 Marco 9 Ruby ------------------------------ Original seats: 8 Final seats: 10
The if i < len(...) guard fills the short column with blanks instead of raising IndexError — the two lists are different lengths by the end. The f-string widths are from Section 6, and worth reusing whenever two lists are compared.