如何删除列表中存在的项?
我通过 self.response.get("new_tag")
从一个表单的文本框获取 new_tag
,然后通过复选框获取 selected_tags
。
self.response.get_all("selected_tags")
我把它们组合成这样:
tag_string = new_tag
new_tag_list = f1.striplist(tag_string.split(",") + selected_tags)
(f1.striplist
是一个函数,用来去掉列表中字符串里的空格。)
但是如果 tag_list
是空的(也就是说没有输入新的标签),但有一些 selected_tags
,那么 new_tag_list
就会包含一个空字符串 " "
。
比如,从 logging.info
输出的内容:
new_tag
selected_tags[u'Hello', u'Cool', u'Glam']
new_tag_list[u'', u'Hello', u'Cool', u'Glam']
我该怎么去掉这个空字符串呢?
如果列表里有一个空字符串:
>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> i = s.index("")
>>> del s[i]
>>> s
[u'Hello', u'Cool', u'Glam']
但如果没有空字符串:
>>> 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"
但是这样得到的结果是:
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
这为什么会发生,我该怎么解决这个问题呢?
8 个回答
try:
s.remove("")
except ValueError:
print "new_tag_list has no empty string"
请注意,这样做只会从你的列表中移除一个空字符串(就像你的代码一样)。你的列表里能有多个空字符串吗?
一句话解决方案:
>>> s = [u'', u'Hello', u'Cool', u'Glam']
>>> s.remove('') if '' in s else None # Does nothing if '' not in s
>>> s
['Hello', 'Cool', 'Glam']
>>>
1) 几乎是英语的风格:
用 in
操作符来检查某个东西是否存在,然后使用 remove
方法来删除它。
if thing in some_list: some_list.remove(thing)
remove
方法只会删除第一个找到的 thing
,如果你想删除所有的,可以用 while
来替代 if
。
while thing in some_list: some_list.remove(thing)
- 这方法很简单,适合小列表(我就是喜欢一行代码)
2) 鸭子类型和EAFP风格:
这种“先做后问”的态度在Python中很常见。与其提前检查对象是否合适,不如直接执行操作,然后捕获相关的错误:
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!")
当然,上面例子中的第二个异常处理部分不仅有点搞笑,而且完全没必要(主要是为了给不熟悉鸭子类型的人做个示范)。
如果你预计会有多个 thing
:
while True:
try:
some_list.remove(thing)
except ValueError:
break
- 对于这个特定的用例来说有点啰嗦,但在Python中很常见。
- 这个方法比第一种更有效。
- PEP 463 提出了一个更简短的 try/except 语法,适合这种情况,但没有被批准。
不过,使用 contextlib的 suppress() 上下文管理器(在Python 3.4中引入),上面的代码可以简化为:
with suppress(ValueError, AttributeError):
some_list.remove(thing)
同样,如果你预计会有多个 thing
:
with suppress(ValueError):
while True:
some_list.remove(thing)
3) 函数式风格:
大约在1993年,Python引入了 lambda
、reduce()
、filter()
和 map()
,这是因为一位怀念这些功能的 Lisp 黑客提交了有效的补丁。你可以用 filter
来从列表中删除元素:
is_not_thing = lambda x: x is not thing
cleaned_list = filter(is_not_thing, some_list)
有一个快捷方式可能对你有用:如果你想过滤掉空项(实际上是 bool(item) == False
的项,比如 None
、零、空字符串或其他空集合),你可以把 None 作为第一个参数传入:
cleaned_list = filter(None, some_list)
- [更新]: 在Python 2.x中,
filter(function, iterable)
等同于[item for item in iterable if function(item)]
(或者如果第一个参数是None
,则等同于[item for item in iterable if item]
);在Python 3.x中,它现在等同于(item for item in iterable if function(item))
。微妙的区别在于,filter以前返回一个列表,现在像生成器表达式一样工作——如果你只是遍历清理后的列表并丢弃它,这样没问题,但如果你真的需要一个列表,就必须用list()
来包裹filter()
调用。 - *这些带有Lisp风格的构造在Python中被认为有点外星人。大约在2005年,Guido甚至谈到要删除
filter
——连同map
和reduce
(它们现在还没被删除,但reduce
被移到了 functools 模块中,如果你喜欢 高阶函数,值得一看)。
4) 数学风格:
列表推导 自从在2.0版本中由 PEP 202 引入后,成为了Python中处理列表的首选风格。其原因是,列表推导提供了一种更简洁的方式来创建列表,适用于当前需要使用 map()
和 filter()
或嵌套循环的情况。
cleaned_list = [ x for x in some_list if x is not thing ]
生成器表达式在2.4版本中由 PEP 289 引入。生成器表达式更适合那些你不需要(或不想)在内存中创建完整列表的情况——比如当你只想逐个遍历元素时。如果你只是遍历列表,可以把生成器表达式看作是一个 惰性求值 的列表推导:
for item in (x for x in some_list if x is not thing):
do_your_thing_with(item)
- 见 这篇Python历史博客,作者是 GvR。
- 这种语法灵感来自于数学中的 集合构造符号。
- Python 3 还引入了 集合 和 字典推导。
注意事项
- 你可能想用不等于操作符
!=
来替代is not
(这个区别很重要) - 对于批评那些暗示列表复制的方法:与普遍看法相反,生成器表达式并不总是比列表推导更高效——请在抱怨之前先进行性能分析。