In How to modify list entries during for loop?, the general recommendation is that it can be unsafe so don't do it unless you know it's safe. In comments under the first answer @martineau says:
It [the loop variable] doesn't make a copies. It just assigns the loop variable name to successive elements or value of the thing being iterated-upon.
That is the behavior I expect and want, but I'm not getting it. I want to remove trailing None
s from each value in the list. My loop variable is modified correctly but the list elements remain unchanged.
How can I get the loop variable fv
to be a pointer to the rows of list foo
, not a copy of the row?
Extra credit: my code is sucky non-pythonic, so a solution using comprehensions or slices instead of for loops would be preferred.
foo = [
['a', 'b', None, None],
['c', None, 'e', None],
['f', None, None, None]
]
desired = [
['a', 'b'],
['c', None, 'e'],
['f']
]
for fv in foo:
for v in range(len(fv) -1, 0, -1):
if fv[v] == None:
fv = fv[:v]
print(f' {v:2} {fv}')
else:
break
print(foo)
The output is:
3 ['a', 'b', None]
2 ['a', 'b']
3 ['c', None, 'e']
3 ['f', None, None]
2 ['f', None]
1 ['f']
[['a', 'b', None, None], ['c', None, 'e', None], ['f', None, None, None]]
The line fv = fv[:v]
will create a new variable named fv
instead of mutating fv
. You should mutate the existing list.
One solution could be using while
to strip unwanted values until none left. The .pop()
method will mutate row
instead of returning a new list:
for row in foo:
while row and row[-1] is None:
row.pop()
assert foo == desired