为什么会产生这个问题?
因为我写了一个有问题的代码,大概长下面这样
# 如下是一个简单的循环
l = ['abc' ,2 ,[1, 2, 3] ,4]
for i in l:
print(i)
l.remove(i)
print(l)
最后的输出是
abc
[1, 2, 3]
[2, 4]
踩坑的原因是,在遍历的时候,我根据一些条件去删除列表中的元素,然后偶然发现输出与我的预期并不符合。
原本的理解是next
会依次返回后面一个元素,因此现在这个元素我删了也没事。
但是事实显然不是这样,列表产生的迭代器返回值好像是根据索引返回的
大模型的回答不同模型直接存在差异,因此在翻了一些 blog ,有一篇里面有句话如下所示
==迭代器本身并不存储任何数据项,存储的只是一个指针,该指针指向可迭代对象中真正存储的数据项,它指向当前被遍历到的数据项索引位置,下一次遍历则向后推进这个位置==
所以再次来求助一下,迭代器的 next 是按照索引来获取数据的吗
1
codehz 66 天前
这就是为啥要删除的话推荐用列表推导式(
实际上没几个语言能在迭代的时候修改原数组的吧( |
2
lisongeee 66 天前
|
3
qianzanqi 66 天前
list_iterator 也就是 type(iter([]))定义在
https://github.com/python/cpython/blob/main/Include/internal/pycore_list.h#L57 成员变量是索引和原本 list __next__逻辑在 https://github.com/python/cpython/blob/main/Objects/listobject.c#L3872 用 PyObject *item = list_get_item_ref(seq, index);获取元素,list_get_item_ref 在读取非法 index 时返回 NULL 从而结束 next 调用。执行完一次 next 后,list_iterator 储存的 index+1 你的例子中,一共调用了 2 次 next 第一次结束 index=0 list=[2, [1, 2, 3], 4] 第二次结束 index=1 list=[2, 4] 第三次调用 next 时,index=2 非法,结束迭代 |
4
qianzanqi 66 天前
@qianzanqi 说例子时的 index 错了
第一次开始 index=0 ,结束时 index=1 list=[2, [1, 2, 3], 4] 第二次开始 index=1 ,结束时 index=2 list=[2, 4] 第三次 index=2 非法 |
6
sgld OP @qianzanqi 感谢大佬,源码大概意思能理解,明确指出了 index + 1 ,FT_ATOMIC_STORE_SSIZE_RELAXED 这些就去问大模型理解了,不太熟悉。
index < 0 就会返回 NUll ,item == NULL 就把 index 设置为-1 。从而退出循环 |
8
cybort 66 天前 via Android
就算不用迭代器也不能一边循环一边 remove 啊
|
9
shinession 66 天前 1
按索引删除的话,要从最大到 0 删除,
for i in range(len(l)-1,-1,-1): print(l[i]) l.pop(i) print(l) |
10
EndlessMemory 65 天前 1
再遍历某个可迭代对象的时候,不要做删除操作
|
11
Lhcfl 65 天前
不要写这样的代码,会跑出 O(n^2 )的时间复杂度,而且如果是 C++的话这是典型的 undefined behaviour ,以及都用 python 了研究迭代器怎么迭代的干什么,把它当成黑盒模型用就好了
|
12
julyclyde 65 天前
所谓指针这个明显是臆测啊
那只是其中一种实现方法,但并不是必须这么实现 |
13
deplives 65 天前
众所周知,遍历对象的时候不要做删除操作
|
14
delphisharp 32 天前
不要在遍历时做改变遍历对象长度的操作。会给自己挖坑的。
就仅仅做打印删除的场景,我用 while 来实现。 |