Is this a safe thing to do?

P

Phil Schmidt

The following example works fine (Python 2.3), but is it always safe
to modify a list that is being iterated in a loop, regardless of the
actual contents of the list x? If not, what's a better (safe) way to
do it?

Thanks!

x=[{'f':9},{'f':1},{1:3,'f':9},{'f':3}]
for t in x:
if t['f'] == 9:
x.remove(t)

[{'f': 1}, {'f': 3}]
 
D

Duncan Booth

(e-mail address removed) (Phil Schmidt) wrote in
The following example works fine (Python 2.3), but is it always safe
to modify a list that is being iterated in a loop, regardless of the
actual contents of the list x? If not, what's a better (safe) way to
do it?

No, it is never safe to do this, you might skip over list elements. For
example, a very small change to your data shows it going wrong:
x=[{'f':9},{'f':1},{1:3,'f':9},{'f':9},{'f':3}]
for t in x:
if t['f'] == 9:
x.remove(t)

x [{'f': 1}, {'f': 9}, {'f': 3}]

The answer is to iterate over a COPY of the list if you want to modify it
during the iteration:
x=[{'f':9},{'f':1},{1:3,'f':9},{'f':9},{'f':3}]
for t in list(x):
if t['f'] == 9:
x.remove(t)


Copying the list may be done by using the 'list' builtin, by using an empty
slice, or using 'copy.copy'.
 
D

David C. Fox

Phil said:
The following example works fine (Python 2.3), but is it always safe
to modify a list that is being iterated in a loop, regardless of the
actual contents of the list x? If not, what's a better (safe) way to
do it?

Thanks!


x=[{'f':9},{'f':1},{1:3,'f':9},{'f':3}]
for t in x:

if t['f'] == 9:
x.remove(t)



[{'f': 1}, {'f': 3}]


This is generally not safe. Another way to do it is

x = filter(lambda t: t['f'] != 9, x)

which creates a new list out of all elements t satisfying t['f'] not
equal to 9, and then assigns the new list back to x.

David
 
T

Terry Reedy

Duncan Booth said:
The answer is to iterate over a COPY of the list if you want to modify it
during the iteration:

or, when deleting items, carefully iterate backwards

x=[{'f':9},{'f':1},{1:3,'f':9},{'f':9},{'f':3}]
for i in range(len(x)-1,-1,-1):
if x['f'] == 9:
del x
[{'f': 1}, {'f': 3}]

Terry J. Reedy
 
L

logistix at cathoderaymission.net

The following example works fine (Python 2.3), but is it always safe
to modify a list that is being iterated in a loop, regardless of the
actual contents of the list x? If not, what's a better (safe) way to
do it?

Thanks!

x=[{'f':9},{'f':1},{1:3,'f':9},{'f':3}]
for t in x:
if t['f'] == 9:
x.remove(t)

[{'f': 1}, {'f': 3}]

This is the perfect place to use a list comprehension:
x=[{'f':9},{'f':1},{1:3,'f':9},{'f':3}]
x = [t for t in x if t['f'] != 9]
x [{'f': 1}, {'f': 3}]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,166
Messages
2,570,903
Members
47,444
Latest member
Michaeltoyler01

Latest Threads

Top