如何删除列表中存在的项?

367 投票
8 回答
691219 浏览
提问于 2025-04-16 11:21

我通过 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 个回答

13
try:
    s.remove("")
except ValueError:
    print "new_tag_list has no empty string"

请注意,这样做只会从你的列表中移除一个空字符串(就像你的代码一样)。你的列表里能有多个空字符串吗?

14

一句话解决方案:

>>> 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']
>>> 
955

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引入了 lambdareduce()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——连同 mapreduce(它们现在还没被删除,但 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)

注意事项

  1. 你可能想用不等于操作符 != 来替代 is not这个区别很重要
  2. 对于批评那些暗示列表复制的方法:与普遍看法相反,生成器表达式并不总是比列表推导更高效——请在抱怨之前先进行性能分析。

撰写回答