2011-07-01 37 views
2

我们知道以下代码只是逐行加载数据,而不是将它们全部加载到内存中。即阅读也会莫名其妙地被标记为“可删除”的OS所有迭代器都缓存吗? csv.Reader怎么样?

def fileGen(file): 
    for line in file: 
     yield line 

with open("somefile") as file: 
    for line in fileGen(file): 
     print line 

但线路alread反正是有,我们可以验证,如果,如果我们修改fileGen的定义,下面这仍然是真的吗?

def fileGen(file): 
    for line in csv.Reader(file): 
     yield line 

我们如何知道csv.Reader是否会缓存它加载的数据?感谢

问候, 约翰

回答

4

最可靠的方法来找出csv.reader正在做的是读取源。见_csv.c,第773行起。您会看到reader对象有一个指向基础迭代器(通常是文件迭代器)的指针,每次需要另一行时它都会调用PyIter_Next。所以它不会预读或以其他方式缓存它加载的数据。

找出csv.reader正在做什么的另一种方法是制作一个模拟文件对象,该对象可以在被查询时进行报告。例如:

class MockFile: 
    def __init__(self): self.line = 0 
    def __iter__(self): return self 
    def next(self): 
     self.line += 1 
     print "MockFile line", self.line 
     return "line,{0}".format(self.line) 

>>> r = csv.reader(MockFile()) 
>>> next(r) 
MockFile line 1 
['line', '1'] 
>>> next(r) 
MockFile line 2 
['line', '2'] 

这证实了我们从阅读csv源代码获悉:它只能从底层迭代器请求的下一行,当自己的next方法被调用。


约翰说得很清楚(见注释),他关心的是csv.reader是否保持线活着,以避免它们被Python的内存管理器收集。

再次,您可以阅读代码(最可靠)或尝试实验。如果您查看中的Reader_iternext的实现,您会看到lineobj是由基础迭代器返回的对象的名称,并且在通过代码的每个路径上都有一个调用Py_DECREF(lineobj)。所以csv.reader不保留lineobj活着。

这里有一个实验来证实这一点。

class FinalizableString(string): 
    """A string that reports its deletion.""" 
    def __init__(self, s): self.s = s 
    def __str__(self): return self.s 
    def __del__(self): print "*** Deleting", self.s 

class MockFile: 
    def __init__(self): self.line = 0 
    def __iter__(self): return self 
    def next(self): 
     self.line += 1 
     return FinalizableString("line,{0}".format(self.line)) 

>>> r = csv.reader(MockFile()) 
>>> next(r) 
*** Deleting line,1 
['line', '1'] 
>>> next(r) 
*** Deleting line,2 
['line', '2'] 

所以你可以看到,csv.reader没有挂到它从迭代器获取对象,如果没有其他让他们活着,那么他们得到的垃圾收集及时。


我有一种感觉,这个问题还有更多的东西,你不告诉我们。你能解释一下你为什么担心这件事吗?

+0

emmm,您对上述代码“没有提前阅读”,但是我们如何知道读者在请求['line',2]之后'hold'['Line',1]?这是我主要关心的问题。 – John

+0

查看已更新的答案(和您的问题)。 –

+0

嗨Gareth,感谢您的更新,我认为我现在对此更有信心,我会仔细查看您提到的c文件以了解详细信息。我正在尝试编写一个脚本来处理一些大尺寸文件,所以我想确保代码不会吃掉所有内存。在我们将数据写回到文件之前,我会做一些缓冲,但也希望确保csv阅读器不会以某种方式'缓存'它加载的数据,否则我的随动缓冲区将变得毫无意义 – John