问题
问题来自于Python技术群的一个提问:
输出结果为:
代码功能很简单,就是给定两个列表keywords和badkeys,从keywords中过滤掉包含bad key的元素。乍一看代码,逻辑上没有问题。那究竟是什么原因导致执行出错了呢?
分析
首先在for循环中加了log:
然后发现keywords中的最后一个元素“哈士奇是个大傻瓜”没有被处理,猜测一定是remove或者循环出了问题。
简单Google一下,果然:
For in 是对下标进行操作,而remove是对值进行操作
remove删除一个元素之后,后续元素下标会前移,前移的这个元素实际上就没处理到
具体到上面的例子:
当For in执行到“哈士奇美丽价格”时,下标为3,然后匹配了bad key,执行了remove操作,删除了该元素。此时下一个元素“哈士奇是个大傻瓜”前移,下标变成了3。For循环继续执行,发现没有下标为4的元素,于是直接退出循环了。这样,最后一个元素就没有被处理到。
解决
想到两种方法:
讲keywords数组先copy一份,然后遍历副本,操作原数组;
123456789copy = keywords[::]if keywords !=None:# for key in copy:for key in keywords:for bkey in bad_keys:if bkey in key:keywords.remove(key)break...开辟一个新数组存储合规的key,不操作原数组;
123456789res = []if keywords !=None:# for key in copy:for key in keywords:for bkey in bad_keys:if bkey in key:breakelse:res.append(key)
总之其实就是一句话:不要在遍历的同时操作循环的主体
PS
上面的方案二里出现了for…else…的语法,这里简单解释一下:
在 python 中,for … else 表示这样的意思,for 中的语句和普通的没有区别,else 中的语句会在循环正常执行完(即 for 不是通过 break 跳出而中断的)的情况下执行,while … else 也是一样。
例如: