不了解Python的csv.reader对象

时间:2014-12-03 06:08:04

标签: python pointers object csv memory

我在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的内容。

谢谢!

3 个答案:

答案 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'