4

我正在尝试删除 Python 中列表的最后一个元素:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
for el in di['children']:
  di['children'].remove(el)

我期望的是

print di
{'a': 3, 'children: []}

但我得到的是

print di
{'a': 3, 'children': [{'c': 6}]}

有人知道出了什么问题吗?

4

7 回答 7

11

正如其他人所解释的那样,您不能在迭代列表时修改它。

您可以在迭代列表的副本时修改列表,但最好只生成一个新的过滤列表:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
di['children'] = [el for el in di['children'] if el not in di['children']]

为什么这样更好?好吧,这意味着您正在避免更改列表,这使您的代码更易于推理,更易于跟踪,通常更易于编写,并且通常更快且更节省空间。您不必担心迭代时变异问题的事实是“更容易推理”部分的完美示例。

在某些情况下,它确实变得更难编写,或者速度更慢,或者空间效率更低,这就是为什么这只是一个指导而不是硬性规则。但至少总是值得思考“我可以将其重写为不可变过滤器而不是突变器吗”,即使答案有时可能会变成“否”。

真的,你的算法不能保证等同于清空整个东西吗?在这种情况下:

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
di['children'] = []
于 2012-10-30T22:42:56.753 回答
6

您不应该在迭代列表时修改它。相反,您应该迭代副本。请参阅python 文档

试试这个...

di = {"a": 3, "children": [{"b": 5}, {"c": 6}]}
for el in di['children'][:]:
    di['children'].remove(el)
于 2012-10-30T22:37:29.087 回答
6

您在迭代列表时正在修改列表 - 当您删除第一个条目时,第二个条目将成为第一个条目并且已到达列表的末尾。相反,使用:

del di["children"][:]

这将保留原始列表(与 不同di["children"] = []),因此如果您对它们有其他引用,它们也会反映截断。

于 2012-10-30T22:40:08.820 回答
4

当您向后浏览列表时,您只能删除循环中的元素。

所以我认为只需像这样将 di['children'] 包装在 reversed() 迭代器中

for el in reversed(di['children']):

这是因为删除元素会导致元素的编号发生变化,并且所有后续元素的数字都会减1。但是,如果您向后退,则不应该关心后续元素的索引,而只关心删除之前的元素。

于 2012-10-30T22:44:02.170 回答
2

您在迭代列表时正在修改列表,这是一个坏主意。

尝试迭代列表的副本,同时从原始列表中删除元素。

于 2012-10-30T22:38:06.573 回答
2
del di['children'][1]

删除列表中的最后一个元素。

于 2012-11-01T21:06:32.727 回答
0
 for i in di:
    if type(di[i])==list:
       di[i]=[]
于 2012-10-31T14:21:16.300 回答