# Can't clear list why?

Hello, this is my first post. The challenge is to clear the list, but somehow it does not wnat me to remove the last element, although 10 is devisible by 2. I also tried to use .clear, but also that doesn’t seem to remove it. Why?

#Write your function here def delete_starting_evens(lst): for i in lst: if i % 2 == 0 : lst.pop(0) elif len(lst) == 1 and i % 2 == 0: lst.clear() else: break return lst #Uncomment the lines below when your function is done #print(delete_starting_evens([4, 8, 10, 11, 12, 15])) print(delete_starting_evens([4, 8, 10]))

`for i in lst:` basically says that the for loop is going to iterate over `lst`. It will start from the first element of `lst` and keep iterating until there are no more elements left i.e. until it reaches the end of the list/iterable.

The problem is that by removing/inserting elements to the list you are iterating over, you are changing the length of the list while you are iterating over it. This can cause unintended consequences such as elements being skipped or being iterated over more than once.

``````def delete_starting_evens(lst):
for i in lst:
if i % 2 == 0 :
lst.pop(0)
else:
break
return lst
``````

Consider the function call where the argument is `[4, 8, 10]`
Taking liberties, a rough sketch of the loop is:

• Loop starts and asks the question: “Is there a next element to be iterated over OR has the end of list been reached?”. It looks at index 0 to decide the answer. At this index, there is an integer element `4`. The iteration begins and per your code, `4` is removed from the list. Now `lst` is `[8, 10]`
• Next iteration. Loop again asks question: “Next Element? OR End of List?”. But it has already looked at index 0, so it looks at index 1 to decide the answer. At this index, there is the integer element `10`. It skipped over `8` because as far as the loop is concerned, it has already taken care of the element at index 0. Iteration begins and per your code, `8` is removed from the list (because of `lst.pop[0]`). Now `lst` is `[10]`
• Next iteration. Loop again asks question: “Next Element? OR End of List?”. But it has already looked at index 1, so it looks at index 2 to decide the answer. This index is beyond the bounds of the list, so for decides it has reached end of list and finishes.

Consider the function call where the argument is `[4, 8, 10, 11, 12, 15]`

• Loop starts and asks the question: “Is there a next element to be iterated over OR has the end of list been reached?”. It looks at index 0 to decide the answer. At this index, there is an integer element `4`. The iteration begins and per your code, `4` is removed from the list. Now `lst` is `[8, 10, 11, 12, 15]`
• Next iteration. Loop again asks question: “Next Element? OR End of List?”. But it has already looked at index 0, so it looks at index 1 to decide the answer. At this index, there is the integer element `10`. It skipped over `8` because as far as the loop is concerned, it has already taken care of the element at index 0. Iteration begins and per your code, `8` is removed from the list (because of `lst.pop[0]`). Now `lst` is `[10, 11, 12, 15]`
• Next iteration. Loop again asks question: “Next Element? OR End of List?”. But it has already looked at index 1, so it looks at index 2 to decide the answer. At this index, there is the integer element `12`. Iteration begins and per your code, `10` is removed from the list (because of `lst.pop[0]`). Now `lst` is `[11, 12, 15]`
• Next iteration. Loop again asks question: “Next Element? OR End of List?”. But it has already looked at index 2, so it looks at index 3 to decide the answer. This index is beyond the bounds of the list, so for decides it has reached end of list and finishes. It is just by good luck rather than sound logic that the output of `[11, 12, 15]` turns out to be correct.
Suppose instead of `[4, 8, 10, 11, 12, 15]`, the argument was `[4, 7, 10, 11, 12, 15]`.
Your function would return the output `[11, 12, 15]` even though the correct answer is `[7, 10, 11, 12, 15]`

Bottom Line: Don’t mutate a list while you are iterating over it unless you are absolutely certain that it is safe to do so.

Try adding a print statement at the top of the loop. That will allow you to see which element of the list is being iterated over.

``````def delete_starting_evens(lst):
for i in lst:
print(i)     # <-- For debugging and testing
if i % 2 == 0 :
...
``````

You could iterate over a copy of the original list. Suppose you tried something like,

``````def delete_starting_evens(lst):
copied_lst = lst
for i in copied_lst:
if i % 2 == 0 :
lst.pop(0)
else:
break
return lst
``````

This won’t work, because `copied_lst = lst` doesn’t actually create a copy of the list. Both variables `lst` and `copied_lst` hold the reference to the same list in memory. If you modify `lst`, you are actually modifying `copied_lst` and vice versa.

``````lst = [4, 9, 12]
copied_lst = lst
lst[2] = 100
print(lst)
# Output: [4, 9, 100]
print(copied_lst)
# Output: [4, 9, 100]
``````

To create a copy of `lst`, you can use slicing or the `list()` type constructor (and a few other ways).

``````# Slicing
lst = [4, 9, 12]
copied_lst = lst[:]
lst[2] = 100
print(lst)
# Output: [4, 9, 100]
print(copied_lst)
# Output: [4, 9, 12]

# Type Constructor
lst = [4, 9, 12]
copied_lst = list(lst)
lst[2] = 100
print(lst)
# Output: [4, 9, 100]
print(copied_lst)
# Output: [4, 9, 12]
``````

So, if you edit your code to the following, it will work:

``````def delete_starting_evens(lst):
for i in lst[:]:    # <-- Iterating over copy of original list
if i % 2 == 0 :
lst.pop(0)   # <-- Changes to original list don't affect copy of list
else:
break
return lst
``````

Slicing or the list type constructor actually create shallow copies. That is good enough for this challenge because the argument is expected to be a list of numbers. However, if there was a list nested within a list, then mutating the nested list in the original list would also mutate the copied list.

``````lst = [4, 9, [12, 32, 22]]
copied_lst = lst[:]
lst[2][1] = 100
print(lst)
# Output: [4, 9, [12, 100, 22]]
print(copied_lst)
# Output: [4, 9, [12, 100, 22]]
``````

For such cases, we can use `deepcopy` from the copy module after importing (copy — Shallow and deep copy operations — Python 3.11.1 documentation).

However, for this challenge, shallow copying is adequate to accomplish the task.

1 Like