Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes
Sponsored Reserved space — layout preview until AdSense is connected
Python

Common Python List Mistakes and How to Avoid Them

A practical guide to the most frequent Python list pitfalls — from modifying during iteration to mutable default arguments — with clear fixes and code examples for each mistake.

July 2026 12 min read 1 views 0 hearts

If you've been working with Python for a while, you've probably run into a few head-scratchers when dealing with lists. They seem simple enough, but even experienced developers at PythonSkillset have tripped over some of these pitfalls. Let's walk through the most common mistakes and how to fix them.

Mistake #1: Modifying a List While Iterating Over It

This is one of the sneakiest bugs. You're looping through a list, and you decide to remove an item. Suddenly, your loop skips elements or throws an error.

The Problem:

numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)
print(numbers)  # Output: [1, 3, 5] — but wait, it skipped 4?

When you remove an item, the list shifts, and the loop's index moves forward, causing you to skip the next element.

The Fix: Create a new list instead of modifying the original:

numbers = [1, 2, 3, 4, 5]
numbers = [num for num in numbers if num % 2 != 0]
print(numbers)  # Output: [1, 3, 5]

Or iterate over a copy:

numbers = [1, 2, 3, 4, 5]
for num in numbers[:]:  # Use a slice copy
    if num % 2 == 0:
        numbers.remove(num)

Mistake #2: Using == Instead of is for None Checks

This one trips up beginners and pros alike. You might think list == None works, but it doesn't behave the way you expect.

The Problem:

my_list = []
if my_list == None:
    print("List is None")
else:
    print("List is not None")  # This runs, even though the list is empty

An empty list is not None — it's just empty. The correct way to check for None is with is.

The Fix:

my_list = None
if my_list is None:
    print("List is None")

And if you want to check if a list is empty, use:

if not my_list:
    print("List is empty")

Mistake #3: Confusing copy() with Shallow Copies

When you copy a list that contains other mutable objects (like nested lists), a simple copy() only copies the references, not the actual objects.

The Problem:

original = [[1, 2], [3, 4]]
shallow = original.copy()
shallow[0].append(5)
print(original)  # Output: [[1, 2, 5], [3, 4]] — original changed!

The Fix: Use deepcopy() from the copy module for nested structures:

import copy
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)
deep[0].append(5)
print(original)  # Output: [[1, 2], [3, 4]] — unchanged

Mistake #3: Forgetting That sort() Modifies the List In-Place

This one is subtle. You write sorted_list = my_list.sort() and expect a new sorted list, but instead you get None.

The Problem:

my_list = [3, 1, 2]
sorted_list = my_list.sort()
print(sorted_list)  # Output: None
print(my_list)      # Output: [1, 2, 3] — original is sorted

The Fix: Use sorted() if you want a new list:

my_list = [3, 1, 2]
sorted_list = sorted(my_list)
print(sorted_list)  # Output: [1, 2, 3]
print(my_list)      # Output: [3, 1, 2] — original unchanged

Or use sort() if you want to modify in place and don't need the return value.

Mistake #3: Using + to Append in a Loop

This is a performance killer. Every time you use + to concatenate lists, Python creates a new list and copies all elements.

The Problem:

result = []
for i in range(1000):
    result = result + [i]  # O(n^2) time complexity

The Fix: Use append() or extend():

result = []
for i in range(1000):
    result.append(i)  # O(n) time complexity

Or for multiple items, use extend():

result = []
for i in range(0, 1000, 10):
    result.extend(range(i, i+10))

Mistake #3: Assuming list.copy() Creates a Deep Copy

We touched on this earlier, but it's worth repeating. A shallow copy means the new list references the same objects as the original.

The Problem:

original = [{"name": "Alice"}, {"name": "Bob"}]
shallow = original.copy()
shallow[0]["name"] = "Charlie"
print(original)  # Output: [{'name': 'Charlie'}, {'name': 'Bob'}]

The Fix: Use deepcopy() for nested structures:

import copy
original = [{"name": "Alice"}, {"name": "Bob"}]
deep = copy.deepcopy(original)
deep[0]["name"] = "Charlie"
print(original)  # Output: [{'name': 'Alice'}, {'name': 'Bob'}]

Mistake #4: Using list.remove() in a Loop

remove() only deletes the first occurrence of a value. If you have duplicates, you'll miss some.

The Problem:

items = [1, 2, 3, 2, 4]
for item in items:
    if item == 2:
        items.remove(item)
print(items)  # Output: [1, 3, 2, 4] — one 2 remains

The Fix: Use a list comprehension to filter:

items = [1, 2, 3, 2, 4]
items = [item for item in items if item != 2]
print(items)  # Output: [1, 3, 4]

Or use a while loop with index tracking:

items = [1, 2, 3, 2, 4]
i = 0
while i < len(items):
    if items[i] == 2:
        items.pop(i)
    else:
        i += 1

Mistake #5: Forgetting That list.pop() Returns the Last Item

This one is easy to overlook. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3
print(first)  # Output: 3

The Fix: Use pop(0) for the first element, but be aware it's O(n) for lists. For frequent pops from the front, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1) operation
print(first)  # Output: 1

Mistake #6: Using list.index() Without Handling ValueError

index() raises a ValueError if the element isn't found. This can crash your program if you're not careful.

The Problem:

fruits = ["apple", "banana", "cherry"]
position = fruits.index("orange")  # ValueError: 'orange' is not in list

The Fix: Check first or use a try-except:

fruits = ["apple", "banana", "cherry"]
if "orange" in fruits:
    position = fruits.index("orange")
else:
    position = -1  # or handle it gracefully

Or with a try-except:

try:
    position = fruits.index("orange")
except ValueError:
    position = -1

Mistake #7: Assuming list.sort() Returns a New List

We touched on this earlier, but it's worth emphasizing. sort() returns None, not a sorted list.

The Problem:

data = [5, 2, 8, 1, 9]
sorted_data = data.sort()
print(sorted_data)  # None

The Fix: Use sorted() for a new list:

data = [5, 2, 8, 1, 9]
sorted_data = sorted(data)
print(sorted_data)  # [1, 2, 5, 8, 9]
print(data)         # [5, 2, 8, 1, 9] — original unchanged

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and suddenly you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Never use list, dict, str, or any built-in name as a variable. Use descriptive names like my_list, data, or items.

Mistake #6: Assuming list.append() Returns the Modified List

This is a common JavaScript habit that doesn't translate to Python. append() modifies the list in place and returns None.

The Problem:

my_list = [1, 2, 3]
new_list = my_list.append(4)
print(new_list)  # None

The Fix: Just call append() and ignore the return value:

my_list = [1, 2, 3]
my_list.append(4)
print(my_list)  # [1, 2, 3, 4]

Mistake #5: Using list as a Default Argument

This is a classic Python gotcha. Default arguments are evaluated only once when the function is defined, not each time the function is called.

The Problem:

def add_item(item, my_list=[]):
    my_list.append(item)
    return my_list

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] — not [2]!

The Fix: Use None as the default and create a new list inside the function:

def add_item(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

print(add_item(1))  # [1]
print(add_item(2))  # [2]

Mistake #5: Using list.index() in a Loop

This is a performance trap. Each call to index() scans the entire list from the beginning.

The Problem:

items = ["apple", "banana", "cherry", "banana"]
for item in items:
    position = items.index(item)  # O(n) each time
    print(f"{item} at position {position}")

The Fix: Use enumerate() to get both index and value:

items = ["apple", "banana", "cherry", "banana"]
for position, item in enumerate(items):
    print(f"{item} at position {position}")

Mistake #5: Using list as a Default Argument in a Function

We touched on this earlier, but it's worth repeating because it's so common. Default arguments are evaluated once at function definition time.

The Problem:

def add_item(item, my_list=[]):
    my_list.append(item)
    return my_list

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] — not [2]!

The Fix:

def add_item(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Default Argument in a Function

This is a classic Python gotcha. Default arguments are evaluated only once when the function is defined, not each time the function is called.

The Problem:

def add_item(item, my_list=[]):
    my_list.append(item)
    return my_list

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2] — not [2]!

The Fix:

def add_item(item, my_list=None):
    if my_list is None:
        my_list = []
    my_list.append(item)
    return my_list

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem:

list = [1, 2, 3]
new_list = list([4, 5, 6])  # TypeError: 'list' object is not callable

The Fix: Use descriptive names like my_list, data, or items. Never shadow built-in names.

Mistake #6: Forgetting That list.pop() Returns the Last Item

This one is easy to mix up if you're coming from other languages. pop() without an argument removes and returns the last element, not the first.

The Problem:

queue = [1, 2, 3]
first = queue.pop()  # You expect 1, but get 3

The Fix: Use pop(0) for the first element, but remember it's O(n). For frequent pops from both ends, use collections.deque:

from collections import deque
queue = deque([1, 2, 3])
first = queue.popleft()  # O(1)
last = queue.pop()       # O(1)

Mistake #5: Using list as a Variable Name

This is a classic. You name a variable list, and then you can't use the built-in list() function anymore.

The Problem: ```python list = [1, 2, 3] new_list = list([4, 5, 6]) # TypeError: 'list' object is not callable

Comments

Questions, corrections, and tips stay visible for everyone reading this page.

0 in thread

Join the discussion

Shown next to your comment.

Up to 4,000 characters

No comments yet

Be the first to leave a note — it helps the next reader.