Python代码在Jupyter Notebook中两次迭代报错问题咨询
问题拆解与解决方案
嘿,这个问题我熟!咱们先说说为啥会报错:
核心问题根源
你用的csv.reader()返回的是个迭代器(iterator),这玩意儿有个特性——只能从头到尾遍历一次!当你第一个for row in reader循环跑完所有行之后,这个迭代器的“指针”就停在文件末尾了,再跑第二个for each in reader循环时,已经没东西可读了,循环根本不会执行。而且你第二个循环里还误用了第一个循环的row变量,这要么会拿到上一次循环最后一行的值,要么直接报变量未定义的错,雪上加霜😂
几种靠谱的解决办法
1. 把所有行存成列表,想遍历多少次都行
先把迭代器转成列表,列表是可以反复遍历的序列,这样两次循环就都能拿到数据了:
import csv csvfile = open("sales_rank.csv") reader = csv.reader(csvfile) header = next(reader) # 把所有行存进列表,以后随便用 all_rows = list(reader) category = {} rank = {} # 第一次遍历处理category for row in all_rows: category.setdefault(row[1], []).append(row[4]) # 第二次遍历处理rank,注意这里要用当前循环的变量each,别再用row了! for each in all_rows: rank.setdefault(each[3], []).append(each[0]) # 别忘了关文件哦 csvfile.close()
2. 一次循环搞定两个字典,高效又省心
其实没必要分两次循环,在同一个循环里同时处理category和rank就好,既省内存又避免迭代器的坑:
import csv category = {} rank = {} # 用with语句自动管文件,不用手动close,超安全 with open("sales_rank.csv") as csvfile: reader = csv.reader(csvfile) header = next(reader) # 一次循环同时填充两个字典 for row in reader: category.setdefault(row[1], []).append(row[4]) rank.setdefault(row[3], []).append(row[0])
这种方式是我最推荐的,代码更简洁,效率也更高,还不会有迭代器的问题。
3. 重置文件指针(不推荐,凑数用的)
如果你非要分开两次循环,那可以在第一次循环后把文件指针移回开头,再重新跳过表头,但这种方法有点啰嗦,大文件的话效率也不高:
import csv csvfile = open("sales_rank.csv") reader = csv.reader(csvfile) header = next(reader) category = {} for row in reader: category.setdefault(row[1], []).append(row[4]) # 把文件指针移回开头,然后再跳过一次表头 csvfile.seek(0) next(reader) rank = {} for each in reader: rank.setdefault(each[3], []).append(each[0]) csvfile.close()
最后提个小坑
你第二次循环里写的rank.setdefault(row[3],[]).append(row[0])绝对要改!这里的row是第一个循环的变量,到第二个循环里它要么是第一个循环最后一行的内容,要么直接报错,一定要改成each[3]和each[0],对应你第二个循环的变量名~
内容的提问来源于stack exchange,提问作者Jefferson
相关产品推荐
相关产品推荐

