我在python的内置csv模块中遇到过一种我以前从未注意过的行为。通常,当我在csv中阅读时,它几乎逐字地跟在doc's之后,使用''打开文件,然后使用' for'循环读取器对象。环。但是,我最近尝试连续两次迭代csv.reader对象,但却发现第二个' for'循环没有做任何事。
import csv
with open('smallfriends.csv','rU') as csvfile:
readit = csv.reader(csvfile,delimiter=',')
for line in readit:
print line
for line in readit:
print 'foo'
控制台输出:
Austins-iMac:Desktop austin$ python -i amy.py
['Amy', 'James', 'Nathan', 'Sara', 'Kayley', 'Alexis']
['James', 'Nathan', 'Tristan', 'Miles', 'Amy', 'Dave']
['Nathan', 'Amy', 'James', 'Tristan', 'Will', 'Zoey']
['Kayley', 'Amy', 'Alexis', 'Mikey', 'Sara', 'Baxter']
>>>
>>> readit
<_csv.reader object at 0x1023fa3d0>
>>>
所以第二个&#39; for&#39;循环基本上什么都不做我有一个想法是csv.reader对象在被读取一次后从内存中释放。但事实并非如此,因为它仍然保留了它的内存地址。我发现post提到了类似的问题。他们给出的原因是,一旦读取了对象,指针就会停留在内存地址的末尾,准备将数据写入对象。它是否正确?有人可以详细了解这里发生了什么吗?有没有办法将指针推回到内存地址的开头重新读取?我知道这样做的编码方法很糟糕,但我主要只是好奇并希望更多地了解Python的内容。
谢谢!
答案 0 :(得分:5)
我会尝试回答您关于读者正在做什么以及为什么reset()
或seek(0)
可能会有所帮助的其他问题。在最基本的形式中,csv阅读器可能看起来像这样:
def csv_reader(it):
for line in it:
yield line.strip().split(',')
也就是说,它需要任何迭代器生成字符串并为您提供生成器。它所做的只是从你的迭代器中获取一个项目,处理它并返回该项目。消耗it
时,csv_reader将退出。读者不知道迭代器的来源或如何正确地制作一个新的,所以它甚至不会尝试重置自己。这留给了程序员。
我们既可以在没有读者知道的情况下修改迭代器,也可以只创建一个新读者。以下是一些证明我的观点的例子。
data = open('data.csv', 'r')
reader = csv.reader(data)
print(next(reader)) # Parse the first line
[next(data) for _ in range(5)] # Skip the next 5 lines on the underlying iterator
print(next(reader)) # This will be the 7'th line in data
print(reader.line_num) # reader thinks this is the 2nd line
data.seek(0) # Go back to the beginning of the file
print(next(reader)) # gives first line again
data = ['1,2,3', '4,5,6', '7,8,9']
reader = csv.reader(data) # works fine on lists of strings too
print(next(reader)) # ['1', '2', '3']
一般情况下,如果您需要第二遍,最好关闭/重新打开文件并使用新的csv阅读器。它干净整洁,确保了很好的簿记。
答案 1 :(得分:1)
迭代csvreader只是包装迭代底层文件对象中的行。 在每次迭代中,阅读器从文件中获取下一行,转换并返回它。
因此迭代csvreader遵循与iterating over files相同的约定。 也就是说,一旦文件到达终点,你必须在第二次迭代之前寻求开始。
下面应该这样做,虽然我还没有测试过它:
import csv
with open('smallfriends.csv','rU') as csvfile:
readit = csv.reader(csvfile,delimiter=',')
for line in readit:
print line
# go back to the start of the file
csvfile.seek(0)
for line in readit:
print 'foo
答案 2 :(得分:0)
如果数据不是太多,您可以随时将其读入列表:
import csv
with open('smallfriends.csv','rU') as csvfile:
readit = csv.reader(csvfile,delimiter=',')
csvdata = list(readit)
for line in csvdata :
print line
for line in csvdata :
print 'foo'