Career upgrade: Learn practical AI skills for better jobs and higher pay.
Level up

Lists, Mutation, Methods, and Aliasing

Key Takeaways

  • Lists are mutable, so item assignment, slice assignment, deletion, and many list methods change the existing list object.
  • Methods such as append, extend, insert, sort, reverse, and clear mutate the list in place and return None.
  • pop mutates the list and returns the removed element, while remove mutates the list and returns None.
  • Assignment such as second = first creates another name for the same list object rather than a copy.
  • Use slicing, list.copy(), or list() for a shallow copy when later top-level list changes should not affect the original.
Last updated: May 2026

Mutable sequence behavior

A list is an ordered, mutable collection. Ordered means positions matter. Mutable means the same list object can be changed after it is created. PCEP questions use this to test whether you can separate the list object from the variable names that refer to it.

scores = [70, 80, 90]
scores[1] = 85
print(scores)  # [70, 85, 90]

The assignment did not create a new list. It changed the object that scores already referenced. Lists can also change through slice assignment, del, and list methods.

Method effects and return values

Many beginner mistakes come from assuming that a method returns the changed list. In Python, the common in-place list methods usually return None. They change the list object directly.

MethodMutates list?Return valueTypical use
append(x)YesNoneAdd one element at the end
extend(iterable)YesNoneAdd each element from another iterable
insert(i, x)YesNoneInsert one element before index i
remove(x)YesNoneRemove first matching value
pop()YesRemoved elementRemove and return last item
sort()YesNoneSort the existing list
reverse()YesNoneReverse the existing list
clear()YesNoneRemove all elements

This code is a classic trap:

values = [3, 1, 2]
result = values.sort()
print(values)  # [1, 2, 3]
print(result)  # None

If you need a new sorted list, use sorted(values). If you use values.sort(), expect the original list to change and the method call itself to evaluate to None.

append versus extend

append() adds one object. extend() iterates through another iterable and adds each element. With strings, that distinction is especially visible.

letters = ['a']
letters.append('bc')
print(letters)  # ['a', 'bc']

letters = ['a']
letters.extend('bc')
print(letters)  # ['a', 'b', 'c']

Aliasing

Assignment does not copy a list. It gives the same list another name.

first = [1, 2]
second = first
second.append(3)
print(first)   # [1, 2, 3]

Both names point at the same object, so mutation through either name is visible through the other. To make a separate top-level list, use a shallow copy:

original = [1, 2]
copy_a = original[:]
copy_b = original.copy()
copy_c = list(original)

A shallow copy is enough when the elements are immutable values such as numbers and strings. It is not a full solution for nested lists, because the inner lists are still shared.

grid = [[1], [2]]
copy = grid[:]
copy[0].append(9)
print(grid)  # [[1, 9], [2]]

Exam strategy

For list questions, mark each operation as either a mutation, a new object creation, or a read. Then write down the method return value. That two-column trace quickly reveals why x = x.append(5) makes x become None, why pop() can be printed, and why aliases see each others mutations.

Test Your Knowledge

What is printed by this code? nums = [3, 1, 2]; x = nums.sort(); print(x)

A
B
C
D
Test Your Knowledge

What is printed? a = [1, 2]; b = a; b.append(3); print(a)

A
B
C
D
Test Your Knowledge

Which list method both changes the list and returns the removed element?

A
B
C
D