Good question, and James’ answer is the only one with actual performance data for Python 2.x for some of the suggested approaches. (See also my comment on that question.)
To complete the picture for Python 3.x, here are a few more tests. Because a single test may modify its list, we need N lists to modify for N tests; therefore I’ve created the set of lists before running a test.
# Python 3.6.2 (default, Jul 18 2017, 14:13:41)
>>> import timeit
>>> number = 10000 # Number of tests.
>>> # Generate `number` lists of 1000 integer elements.
>>> setup = """
... lists=[[_ for _ in range(1000)] for _ in range(10000)]
... i = 0
... """
>>>
All tests, whether they modify a list in place of generate a new one, iterate over that set of lists, to ensure that the conditions for the tests are the same. For simplicity’s sake, all tests remove a single element from the middle of the list.
Let’s start with the examples from the question using the built-in list() functions:
# remove()
>>> stmt = """
... l = lists[i] # Get the current work list.
... l.remove(500) # Remove element.
... i += 1 # On to the next list.
... """
>>> timeit.timeit(stmt, setup=setup, number=number)
0.08474616194143891
# pop()
>>> stmt = "l = lists[i]; l.pop(500); i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.01088976499158889
# index() and pop()
>>> stmt = "l = lists[i]; l.pop(l.index(500)); i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.08841867197770625
# del
>>> stmt = "l = lists[i]; del l[500]; i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.008702976978383958
# index() and del
>>> stmt = "l = lists[i]; del l[l.index(500)]; i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.08238211390562356
List comprehensions as outlined in Ashwini Chaudhary’s answer:
>>> stmt = "l = lists[i]; [_ for _ in l if _ != 500]; i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.44951551605481654
Using filter() as outlined in Loïc Faure-Lacroix’s answer. Note, however, that the examples in the above answer return a filter
object for Python 3.x, and not a list like they do for Python 2.x!
# Generate a filter object.
>>> stmt = "l=lists[i]; filter(lambda _: _ != 500, l); i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
0.0031418869039043784
# Generate a list from the filter object.
>>> stmt = "l=lists[i]; list(filter(lambda _: _ != 500, l)); i += 1"
>>> timeit.timeit(stmt, setup=setup, number=number)
1.1863253980409354
Removing an element that does not exist using Python’s built-in functions requires an additional test; the list comprehension and the filter solution handle non-existing list elements gracefully.
# Catch a resulting exception.
>>> stmt = """
... l = lists[i]
... try:
... del l[l.index(1234)]
... except ValueError:
... pass
... i += 1
... """
>>> timeit.timeit(stmt, setup=setup, number=number)
0.1451275929575786
# Test if the element exists, then delete.
>>> stmt = """
... l = lists[i]
... if 1234 in l:
... del l[l.index[1234]]
... i += 1
... """
>>> timeit.timeit(stmt, setup=setup, number=number)
0.13344507792498916
I hope I got this right.