I am getting
new_tag from a form text field with
selected_tags from checkbox fields with
I combine them like this:
tag_string = new_tag new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
f1.striplist is a function that strips white spaces inside the strings in the list.)
But in the case that
tag_list is empty (no new tags are entered) but there are some
new_tag_list contains an empty string
For example, from
new_tag selected_tags[u'Hello', u'Cool', u'Glam'] new_tag_list[u'', u'Hello', u'Cool', u'Glam']
How do I get rid of the empty string?
If there is an empty string in the list:
>>> s = [u'', u'Hello', u'Cool', u'Glam'] >>> i = s.index("") >>> del s[i] >>> s [u'Hello', u'Cool', u'Glam']
But if there is no empty string:
>>> s = [u'Hello', u'Cool', u'Glam'] >>> if s.index(""): i = s.index("") del s[i] else: print "new_tag_list has no empty string"
But this gives:
Traceback (most recent call last): File "<pyshell#30>", line 1, in <module> if new_tag_list.index(""): ValueError: list.index(x): x not in list
Why does this happen, and how do I work around it?
Test for presence using the
in operator, then apply the
if thing in some_list: some_list.remove(thing)
removemethod will remove only the first occurrence of
thing, in order to remove all occurrences you can use
while instead of
while thing in some_list: some_list.remove(thing)
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
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)
Around 1993, Python got
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)
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
filter- along with companions
reduce(they are not gone yet but
reducewas moved into the functools module, which is worth a look if you like high order functions).
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
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)
is not(the difference is important)
try: s.remove("") except ValueError: print "new_tag_list has no empty string"
Note that this will only remove one instance of the empty string from your list (as your code would have, too). Can your list contain more than one?