1) Almost-English style:
Test for presence using the in
operator, then apply the remove
method.
if thing in some_list: some_list.remove(thing)
The remove
method will remove only the first occurrence of thing
, in order to remove all occurrences you can use while
instead of if
.
while thing in some_list: some_list.remove(thing)
- Simple enough, probably my choice.for small lists (can't resist one-liners)
This shoot-first-ask-questions-last attitude is common in Python. Instead of testing in advance if the object is suitable, just carry out the operation and catch relevant Exceptions:
try:
some_list.remove(thing)
except ValueError:
pass # or scream: thing not in some_list!
except AttributeError:
call_security("some_list not quacking like a list!")
Off course the second except clause in the example above is not only of questionable humor but totally unnecessary (the point was to illustrate duck-typing for people not familiar with the concept).
If you expect multiple occurrences of thing:
while True:
try:
some_list.remove(thing)
except ValueError:
break
- a little verbose for this specific use case, but very idiomatic in Python.
- this performs better than #1
- PEP 463 proposed a shorter syntax for try/except simple usage that would be handy here, but it was not approved.
However, with contextlib's suppress() contextmanager (introduced in python 3.4) the above code can be simplified to this:
with suppress(ValueError, AttributeError):
some_list.remove(thing)
Again, if you expect multiple occurrences of thing:
with suppress(ValueError):
while True:
some_list.remove(thing)
3) Functional style:
Around 1993, Python got lambda
, reduce()
, filter()
and map()
, courtesy of a Lisp hacker who missed them and submitted working patches*. You can use filter
to remove elements from the list:
is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)
There is a shortcut that may be useful for your case: if you want to filter out empty items (in fact items where bool(item) == False
, like None
, zero, empty strings or other empty collections), you can pass None as the first argument:
cleaned_list = filter(None, some_list)
- [update]: in Python 2.x,
filter(function, iterable)
used to be equivalent to [item for item in iterable if function(item)]
(or [item for item in iterable if item]
if the first argument is None
); in Python 3.x, it is now equivalent to (item for item in iterable if function(item))
. The subtle difference is that filter used to return a list, now it works like a generator expression - this is OK if you are only iterating over the cleaned list and discarding it, but if you really need a list, you have to enclose the filter()
call with the list()
constructor.
- *These Lispy flavored constructs are considered a little alien in Python. Around 2005, Guido was even talking about dropping
filter
- along with companions map
and reduce
(they are not gone yet but reduce
was moved into the functools module, which is worth a look if you like high order functions).
4) Mathematical style:
List comprehensions became the preferred style for list manipulation in Python since introduced in version 2.0 by PEP 202. The rationale behind it is that List comprehensions provide a more concise way to create lists in situations where map()
and filter()
and/or nested loops would currently be used.
cleaned_list = [ x for x in some_list if x is not thing ]
Generator expressions were introduced in version 2.4 by PEP 289. A generator expression is better for situations where you don't really need (or want) to have a full list created in memory - like when you just want to iterate over the elements one at a time. If you are only iterating over the list, you can think of a generator expression as a lazy evaluated list comprehension:
for item in (x for x in some_list if x is not thing):
do_your_thing_with(item)
Notes
- you may want to use the inequality operator
!=
instead of is not
(the difference is important)
- for critics of methods implying a list copy: contrary to popular belief, generator expressions are not always more efficient than list comprehensions - please profile before complaining