从列表中删除项目 - 在迭代过程中 - 这个成语有什么问题?[重复]

2025-02-08 08:52:00
admin
原创
45
摘要:问题描述:作为一个实验,我做了以下事情:letters=['a','b','c','d','e','f','g','h','i','j','k','l'] for i in letters: letters.remove(i) print letters 最后的打印显示并非所有项目都被删除了?(其他每...

问题描述:

作为一个实验,我做了以下事情:

letters=['a','b','c','d','e','f','g','h','i','j','k','l']
for i in letters:
    letters.remove(i)
print letters

最后的打印显示并非所有项目都被删除了?(其他每个项目都被删除了)。

IDLE 2.6.2      
>>> ================================ RESTART ================================
>>> 
['b', 'd', 'f', 'h', 'j', 'l']
>>> 

这该如何解释?如何重写该代码以删除所有项目?


解决方案 1:

有些答案解释了为什么会发生这种情况,有些则解释了你应该做什么。我会毫不犹豫地把这些碎片拼凑起来。


这是什么原因呢?

因为 Python 语言的设计目的不同,它处理这种用例的方式也不同。文档中说得很清楚:

在循环中修改正在迭代的序列是不安全的(这只可能发生在可变序列类型中,例如列表)。如果您需要修改正在迭代的列表(例如,复制选定的项目),则必须迭代副本

重点是我。请参阅链接页面了解更多信息 —— 本文档受版权保护,保留所有权利。

您可能很容易理解为什么会得到这样的结果,但这基本上是一种未定义的行为,并且很容易在每次构建过程中发生改变,且没有任何警告。千万不要这样做。

这就像想知道为什么i += i++ + ++i那一行代码会在你的架构上、在你为你的语言构建的编译器上产生这样的效果——包括但不限于破坏你的电脑和让恶魔从你的鼻子里飞出来:)


如何重写它以删除每个项目?

  • del letters[:](如果您需要更改对该对象的所有引用)

  • letters[:] = [](如果您需要更改对该对象的所有引用)

  • letters = [](如果您只想使用新对象)

也许您只是想根据条件删除一些项目?在这种情况下,您应该迭代列表的副本。制作副本的最简单方法是使用以下语法制作包含整个列表的切片[:],如下所示:

#remove unsafe commands
commands = ["ls", "cd", "rm -rf /"]
for cmd in commands[:]:
  if "rm " in cmd:
    commands.remove(cmd)

如果你的检查不是特别复杂,你可以(也可能应该)进行过滤:

commands = [cmd for cmd in commands if not is_malicious(cmd)]

解决方案 2:

您不能同时迭代列表并对其进行变异,而是迭代切片:

letters=['a','b','c','d','e','f','g','h','i','j','k','l']
for i in letters[:]: # note the [:] creates a slice
     letters.remove(i)
print letters

也就是说,对于像这样的简单操作,您应该简单地使用:

letters = []

解决方案 3:

您不能修改正在迭代的列表,否则会得到这种奇怪的结果。为此,您必须迭代列表的副本:

for i in letters[:]:
  letters.remove(i)

解决方案 4:

它删除第一个出现的位置,然后检查序列中的下一个数字。由于序列已经改变,因此它取下一个奇数,依此类推...

  • 取“a”

  • 删除“a” -> 第一个项目现在是“b”

  • 采取下一个项目“c”-...

解决方案 5:

你想要做的是:

letters[:] = []

或者

del letters[:]

letters这将保留指向的原始对象。其他选项(例如letters = [])将创建一个新对象并指向letters它:旧对象通常会在一段时间后被垃圾收集。

并非所有值都被删除的原因是您在迭代列表时更改了列表。

ETA:如果您想从列表中过滤值,您可以使用列表推导,如下所示:

>>> letters=['a','b','c','d','e','f','g','h','i','j','k','l']
>>> [l for l in letters if ord(l) % 2]
['a', 'c', 'e', 'g', 'i', 'k']

解决方案 6:

python 可能使用指针,删除从前面开始。第二行中的变量“letters”与第三行中的变量“letters”部分值不同。当 i 为 1 时,a 被删除,当 i 为 2 时,b 已移动到位置 1,c 被删除。您可以尝试使用“while”。

解决方案 7:

    #!/usr/bin/env python
    import random
    a=range(10)

    while len(a):
        print a
        for i in a[:]:
            if random.random() > 0.5:
                print "removing: %d" % i
                a.remove(i)
            else:
                print "keeping: %d"  % i           

    print "done!"
    a=range(10)

    while len(a):
        print a
        for i in a:
            if random.random() > 0.5:
                print "removing: %d" % i
                a.remove(i)
            else:
                print "keeping: %d"  % i           

    print "done!"

我认为这更好地解释了这个问题,上面的代码块有效,而下面的代码块无效。

“保留”在底部列表中的项目永远不会被打印出来,因为您正在修改正在迭代的列表,这是一个灾难的根源。

解决方案 8:

好吧,我来晚了,但我一直在思考这个问题,在看了 Python (CPython) 的实现代码后,我找到了一个我喜欢的解释。如果有人知道为什么它很愚蠢或错误,我将非常感激。

问题是使用迭代器遍历列表,同时允许该列表发生变化。

迭代器所要做的就是告诉您(在本例中)列表中的哪个项位于当前项之后(即使用 next() 函数)。

我认为迭代器当前实现的方式是,它们只跟踪它们迭代的最后一个元素的索引。查看 iterobject.c 可以看到迭代器的定义:

typedef struct {
    PyObject_HEAD
    Py_ssize_t it_index;
    PyObject *it_seq; /* Set to NULL when iterator is exhausted */
} seqiterobject;

指向it_seq被迭代的序列并it_index给出迭代器提供的最后一项的索引。

当迭代器刚刚提供第 n个项并从序列中删除该项时,后续列表元素与其索引之间的对应关系会发生变化。就迭代器而言,前 (n+1)个项变为第 n个项。换句话说,迭代器现在认为序列中的“下一个”项实际上是“当前”项。

因此,当被要求给出下一个项目时,它将给出前 (n+2)个项目(即新的 (n+1)个项目)。

因此,对于上述代码,迭代器next()方法将仅给出原始列表中的 n+0、n+2、n+4、... 个元素。n+1、n+3、n+5、... 个项目永远不会暴露给该remove 语句。

尽管所讨论代码的预期活动很明确(至少对于人来说),但迭代器可能需要更多的自省来监视其迭代序列的变化,然后以“人性化”的方式行事。

如果迭代器可以返回序列的先前或当前元素,则可能存在通用的解决方法,但事实上,您需要迭代列表的副本,并确保在迭代器到达它们之前不要删除任何项目。

解决方案 9:

最初 i是引用,当循环运行时,第一个位置元素被删除或移除,而第二个位置元素占据第一个位置,但指针移动到第二个位置,这种情况继续下去,这就是我们无法删除的原因b,d,f,h,j,l

`

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1590  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1361  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   18  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   18  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   19  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用