Difficulty: Intermediate
Python lists come with a rich set of built-in methods that let you add, remove, search, and reorder elements. Mastering these methods is essential for writing clean, efficient Python code. Most list methods modify the list in place and return None, which is a common source of confusion for beginners who try to assign the result to a variable.
For adding elements, you have three main methods. append(item) adds a single item to the end of the list in O(1) amortized time. extend(iterable) takes any iterable and adds each of its elements to the end of the list, essentially concatenating them. insert(index, item) places an item at the specified index, shifting all subsequent elements one position to the right, which runs in O(n) time since elements must be moved in memory.
For removing elements, remove(value) deletes the first occurrence of the specified value and raises a ValueError if not found. pop(index) removes and returns the element at the given index (defaulting to the last element if no index is given). pop() from the end is O(1), but pop(0) from the beginning is O(n) because all remaining elements must shift. If you need frequent removals from both ends, consider using collections.deque instead.
The sort() method sorts the list in place using the Timsort algorithm, which runs in O(n log n) time. It accepts two optional keyword arguments: key (a function applied to each element for comparison) and reverse (a boolean to sort in descending order). It modifies the original list and returns None. If you need a new sorted list without modifying the original, use the built-in sorted() function instead.
The reverse() method reverses the list in place in O(n) time and returns None. The copy() method creates a shallow copy of the list, meaning it creates a new list object but the elements themselves are not copied. For lists containing mutable objects like other lists or dictionaries, you need copy.deepcopy() from the copy module to create fully independent copies.
fruits = ["apple", "banana"]
# append adds one item to the end
fruits.append("cherry")
print(fruits)
# extend adds all items from an iterable
fruits.extend(["date", "elderberry"])
print(fruits)
# insert at a specific position
fruits.insert(1, "avocado")
print(fruits)
append() adds to the end, extend() merges another iterable, and insert() places an element at a specific index. All three modify the list in place and return None.
nums = [10, 20, 30, 40, 50, 30]
# remove first occurrence of value
nums.remove(30)
print(nums)
# pop removes and returns by index
last = nums.pop()
print(last)
print(nums)
first = nums.pop(0)
print(first)
print(nums)
# clear removes all elements
nums.clear()
print(nums)
remove() finds by value and deletes the first match. pop() removes by index and returns the removed element. pop() with no argument removes the last element. clear() empties the entire list.
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
# sort ascending in place
numbers.sort()
print(numbers)
# sort descending
numbers.sort(reverse=True)
print(numbers)
# sort by custom key
words = ["banana", "pie", "apple", "fig"]
words.sort(key=len)
print(words)
# reverse in place
words.reverse()
print(words)
sort() modifies the list in place and returns None. Use the key parameter for custom sort logic. reverse() reverses element order in place. For a new sorted list without modifying the original, use the built-in sorted() function.
original = [1, 2, 3]
shallow = original.copy()
shallow.append(4)
print(original)
print(shallow)
# Shallow copy gotcha with nested lists
nested = [[1, 2], [3, 4]]
shallow_nested = nested.copy()
shallow_nested[0][0] = 99
print(nested)
print(shallow_nested)
copy() creates a new list object, so appending to the copy does not affect the original. However, for nested lists, inner objects are shared. Modifying a nested element in the copy also modifies the original. Use copy.deepcopy() for fully independent copies.
append(), extend(), insert(), remove(), pop(), sort(), reverse(), copy()