Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Removing last element of a list in Python fails

I'm trying to remove the last element of a list in Python:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
for el in di['children']:
  di['children'].remove(el)

What I'd expect is

print di
{'a': 3, 'children: []}

But what I get is

print di
{'a': 3, 'children': [{'c': 6}]}

Does anybody have an idea what's going wrong?

like image 253
Martin Nigsch Avatar asked Nov 28 '22 07:11

Martin Nigsch


1 Answers

As everyone else has explained, you can't modify a list while iterating over it.

You can modify a list while iterating over a copy of it, but it's probably better to just generate a new filtered list:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
di['children'] = [el for el in di['children'] if el not in di['children']]

Why is this better? Well, it means you're avoiding mutating the list, which makes your code easier to reason about, easier to trace through, usually easier to write, and often faster and more space-efficient. The fact that you don't have to worry about mutating-while-iterating problems is a perfect example of the "easier to reason about" part.

In some cases, it does turn out to be harder to write, or slower, or less space-efficient, which is why this is just a guideline rather than a hard rule. But it's always at least worth thinking "can I rewrite this as an immutable filter instead of a mutator", even if the answer may sometimes turn out to be "no".

Also really, isn't your algorithm guaranteed to be equivalent to just emptying the whole thing out? In that case:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
di['children'] = []
like image 194
abarnert Avatar answered Dec 04 '22 12:12

abarnert