最可靠的方法来找出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
没有挂到它从迭代器获取对象,如果没有其他让他们活着,那么他们得到的垃圾收集及时。
我有一种感觉,这个问题还有更多的东西,你不告诉我们。你能解释一下你为什么担心这件事吗?
emmm,您对上述代码“没有提前阅读”,但是我们如何知道读者在请求['line',2]之后'hold'['Line',1]?这是我主要关心的问题。 – John
查看已更新的答案(和您的问题)。 –
嗨Gareth,感谢您的更新,我认为我现在对此更有信心,我会仔细查看您提到的c文件以了解详细信息。我正在尝试编写一个脚本来处理一些大尺寸文件,所以我想确保代码不会吃掉所有内存。在我们将数据写回到文件之前,我会做一些缓冲,但也希望确保csv阅读器不会以某种方式'缓存'它加载的数据,否则我的随动缓冲区将变得毫无意义 – John