为何无法在同一个with代码块中两次遍历CSV reader对象的行?
为什么第二次遍历csv.reader对象拿不到数据?
这个问题的核心其实是Python里**迭代器(iterator)**的特性,咱们来掰扯清楚:
原因解析
csv.reader()返回的是一个迭代器,而不是像列表那样可以反复遍历的容器。迭代器的工作逻辑是:每次调用它的__next__()方法(for循环会自动做这件事)就生成一个元素,直到所有元素都被取完,之后再调用就会抛出StopIteration异常——反映到代码里就是遍历的时候拿不到任何数据了。
看你的代码:第一次for row in reader已经把CSV里的所有行都遍历完了,此时这个reader迭代器已经“耗尽”了。后面再用for row in reader去遍历,自然就没有新的元素可以生成,所以m和n都会是空列表。
顺带提一句:文件对象f本身也是一个迭代器,第一次遍历reader的时候,文件指针已经移到了文件末尾,就算你不耗尽reader,直接再读文件也拿不到内容,不过这里主要是reader作为迭代器的问题。
解决方案
根据你的需求,有几种不同的处理方式:
1. 把reader转成列表(适合小文件)
如果你的CSV文件不大,可以先把所有行一次性加载到一个列表里,之后想遍历多少次就遍历多少次:
import csv with open('exercise.csv') as f: reader = csv.reader(f) rows = list(reader) # 将迭代器转为列表,一次性加载所有行 x, y, z = [], [], [] for row in rows: x.append(row[0]) y.append(row[0]) z.append(row[1]) print(len(x), len(y), len(z)) m, n = [], [] for row in rows: m.append(row[0]) for row in rows: n.append(row[1]) print(len(m), len(n))
2. 重置文件指针,重新创建reader(适合大文件)
如果文件很大,不想把所有内容加载到内存里,可以把文件指针移回开头,然后重新生成一个reader对象:
import csv with open('exercise.csv') as f: reader = csv.reader(f) x, y, z = [], [], [] for row in reader: x.append(row[0]) y.append(row[0]) z.append(row[1]) print(len(x), len(y), len(z)) f.seek(0) # 将文件指针移回到文件开头 reader = csv.reader(f) # 重新创建一个reader迭代器 m, n = [], [] for row in reader: m.append(row[0]) n.append(row[1]) # 这里可以一次遍历同时填充m和n,更高效 print(len(m), len(n))
3. 一次遍历完成所有数据收集(最优解)
其实最高效的方式是在第一次遍历的时候就把所有需要的数据都收集好,根本不需要第二次遍历:
import csv with open('exercise.csv') as f: reader = csv.reader(f) x, y, z, m, n = [], [], [], [], [] for row in reader: x.append(row[0]) y.append(row[0]) z.append(row[1]) m.append(row[0]) n.append(row[1]) print(len(x), len(y), len(z)) print(len(m), len(n))
这样既节省内存,又避免了迭代器耗尽的问题,一举两得~
内容的提问来源于stack exchange,提问作者Yuq S
相关产品推荐
相关产品推荐

