Все ли итераторы кешируют? Как насчет csv.Reader? - PullRequest
2 голосов
/ 01 июля 2011

Мы знаем, что следующий код загружает данные только построчно, а не загружает их все в память. то есть прочитанная строка будет как-то помечена как «удаляемая» для ОС

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

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

но можем ли мы в любом случае проверить, верно ли это, если мы изменим определение fileGen на следующее?

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

Как мы могли узнать, будет ли csv.Reader кэшировать загруженные данные? спасибо

С уважением, John

1 Ответ

4 голосов
/ 01 июля 2011

Самый надежный способ узнать, что делает 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 в _csv.c, вы увидите, что 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 не цепляется за объекты, которые он получает от своего итератора, и если ничто иное не поддерживает их, то они своевременно собираются в мусор.


У меня такое ощущение, что в этом вопросе есть что-то большее, чего вы нам не говорите. Не могли бы вы объяснить, почему вас это беспокоит?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...