由于个人技术能力有限,本文章有猜测成分,并不能证明for loop的实质确确实实就是这样。 由于我Google了一下没有人对此问题写过文章,发过提问或者解过答(可能有国外文章有解释,因为我只搜索了中文页面,只稍稍浏览了一下我能看懂的英文页面),故写此文 如需寻起根本,请查看CPython源代码 (为什么我不去看源码?因为我看不懂)
起因 在做题时有一道题,具体的已经忘记了,那里面有个让我很迷惑的for loop,让我以为是题目出错了,结果并不是。
1 2 3 4 5 6 7 s1 = 'v?a?s1?2df34g?h43j?4kl' s = '' for i in s1: if i != '?' : s += i s1 = s
我觉得有问题的代码如上 按照我的理解,如果s1的第一个字符不是'?'
,那么s += i;s1 = s
将会被执行,s
将变成i
,s1
将变成s
,按照上面给的数据,s1
将变成单个字符v
,然后循环结束,但事实不是这个样子的
经过 第一次尝试 1 2 3 4 a = [1 , 2 , 3 , 4 , 5 , 6 ] for i in a: print (i) a = [114514 ]
得到了
这与原题的现象是一致的,但当我不直接给a赋值,而是改变a本身时
1 2 3 4 a = [1 , 2 , 3 , 4 , 5 , 6 ] for i in a: print (i) a.pop()
得到了
每次执行print()
之后都删除最后一个元素,所以只打印出了前三个元素,非常有道理是吧
第二次尝试 那为什么对a赋值就不行了呢 显然是python的底层原理问题,再看一个例子
1 2 3 4 5 6 7 8 9 a = [1 , 2 , 3 , 4 , 5 , 6 ] print (f'原始{id (a)=} ' )for i in a: print (i, '-' , f'{id (i)=} ' ) print (f'(前):循环体中的{id (a)=} ' ) a = [1 , 1 , 4 , 5 , 1 , 4 ] print (f'(后):循环体中的{id (a)=} ' ) print (f'{id ([1 , 1 , 4 , 5 , 1 , 4 ])=} ' ) print ('分割线' .center(100 , '-' ))
得到了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 原始id(a)=1704550319360 1 - id(i)=140728482469648 (前):循环体中的id(a)=1704550319360 (后):循环体中的id(a)=1704550399744 id([1, 1, 4, 5, 1, 4])=1704551518784 ------------------------------------------------分割线------------------------------------------------- 2 - id(i)=140728482469680 (前):循环体中的id(a)=1704550399744 (后):循环体中的id(a)=1704551518784 id([1, 1, 4, 5, 1, 4])=1704550399744 ------------------------------------------------分割线------------------------------------------------- 3 - id(i)=140728482469712 (前):循环体中的id(a)=1704551518784 (后):循环体中的id(a)=1704550399744 id([1, 1, 4, 5, 1, 4])=1704551518784 ------------------------------------------------分割线------------------------------------------------- 4 - id(i)=140728482469744 (前):循环体中的id(a)=1704550399744 (后):循环体中的id(a)=1704551518784 id([1, 1, 4, 5, 1, 4])=1704550399744 ------------------------------------------------分割线------------------------------------------------- 5 - id(i)=140728482469776 (前):循环体中的id(a)=1704551518784 (后):循环体中的id(a)=1704550399744 id([1, 1, 4, 5, 1, 4])=1704551518784 ------------------------------------------------分割线------------------------------------------------- 6 - id(i)=140728482469808 (前):循环体中的id(a)=1704550399744 (后):循环体中的id(a)=1704551518784 id([1, 1, 4, 5, 1, 4])=1704550399744 ------------------------------------------------分割线-------------------------------------------------
id()是什么? f’{…=}’是什么?
可以清晰看到a指向的内存区域不断变化,确实和最原始的a不同了
(后):循环体中的id(a) 与 id([1, 1, 4, 5, 1, 4]) 不停交换是因为a频繁赋同样的值,a总得做出改变 ,但又为了节省空间 ,python创建了两个[1, 1, 4, 5, 1, 4]列表对象,每次a就换一个内存区域指
但是输出的元素还是最原始的a
结论 python for loop的实质是取地址 严格来说是python for loop 迭代可迭代对象时的实质 毕竟其他情况我不知道,没实验过 进入for i in a
的循环体后,i的变化只在最原始的a映射范围内移动 无论之后a被重新指向了哪里,i的变化只在最原始的a映射范围内移动 为什么改变a本身时奇怪现象不存在呢,因为a并没有指向新地址,a的地址对应的映射关系确实发生了改变(即a的元素发生改变),i的变化只在最原始的a映射范围内移动