l = [1,2,3,4] * 10
for idx, n in enumerate(l):
    if n == 3: del l[idx]
This works, giving [1, 2, 4, 1, 2, 4, 1, 2, 4 ...]. Why? Shouldn't the first deletion throw all the indices off? Is Python silently modifying its behavior DWIM-style?
l = [1,2,3,4] * 10
for idx, n in enumerate(l):
    if n == 3: del l[idx]
This works, giving [1, 2, 4, 1, 2, 4, 1, 2, 4 ...]. Why? Shouldn't the first deletion throw all the indices off? Is Python silently modifying its behavior DWIM-style?
 
    
    It actually isn't iterating over all the elements, it's just that your code misses that fact.
You can demonstrate that with the following, which doesn't print anything:
l = [1,2,3,4] * 10
for idx, n in enumerate(l):
    if n == 3: del l[idx]
    elif n == 4: print('saw 4')
You might be interested in my answer to the related question How to modify list entries during for loop?
