Python - лучший способ прочитать файл и разбить строки разделителем - PullRequest
0 голосов
/ 13 октября 2011

Как лучше всего читать файл и разбивать строки разделителем.Возвращаемые данные должны быть списком кортежей.

Можно ли обойти этот метод?Можно ли сделать это быстрее / использовать меньше памяти?

def readfile(filepath, delim):
    with open(filepath, 'r') as f:
        return [tuple(line.split(delim)) for line in f]

Ответы [ 2 ]

14 голосов
/ 13 октября 2011

Ваш опубликованный код считывает весь файл и создает копию файла в памяти в виде единого списка всего содержимого файла, разбитого на кортежи, по одному кортежу на строку. Поскольку вы спрашиваете, как использовать меньше памяти, вам может понадобиться только функция генератора:

def readfile(filepath, delim): 
    with open(filepath, 'r') as f: 
        for line in f:
            yield tuple(line.split(delim))

НО! Существует серьезная оговорка! Вы можете перебирать кортежи, возвращенные readfile, только один раз.

lines_as_tuples = readfile(mydata,','):

for linedata in lines_as_tuples:
    # do something

Пока все в порядке, генератор и список выглядят одинаково. Но предположим, что ваш файл будет содержать много чисел с плавающей запятой, и ваша итерация по файлу вычислит общее среднее из этих чисел. Вы можете использовать код «# do what» для вычисления общей суммы и количества чисел, а затем вычислить среднее значение. Но теперь предположим, что вы хотели повторить итерацию, на этот раз, чтобы найти отличия от среднего для каждого значения. Вы бы подумали, что просто добавите еще один цикл:

for linedata in lines_as_tuples:
    # do another thing
    # BUT - this loop never does anything because lines_as_tuples has been consumed!

БАМ! Это большая разница между генераторами и списками. На данный момент в коде генератор полностью использован - но особых исключений не возникает, цикл for просто ничего не делает и продолжает молча!

Во многих случаях список, который вы получите, будет повторяться только один раз, и в этом случае преобразование файла чтения в генератор будет правильным. Но если вам нужен более постоянный список, к которому вы будете обращаться несколько раз, то простое использование генератора создаст вам проблемы, поскольку вы можете перебирать генератор только один раз.

Мое предложение? Сделайте readlines генератором, чтобы в своем собственном небольшом представлении о мире он просто выдавал каждый инкрементный бит файла, красиво и эффективно занимая память. Возьмите на себя ответственность за сохранение данных на вызывающем объекте - если вызывающий объект должен ссылаться на возвращенные данные несколько раз, то вызывающий элемент может просто создать свой собственный список из генератора - это легко сделать в Python, используя list(readfile('file.dat', ',')).

3 голосов
/ 13 октября 2011

Использование памяти можно сократить, используя генератор вместо списка и список вместо кортежа, поэтому вам не нужно считывать весь файл в память сразу:

def readfile(path, delim):
    return (ln.split(delim) for ln in open(f, 'r'))

Вам придется полагаться на сборщик мусора, чтобы закрыть файл. Что касается возврата кортежей: не делайте этого, если в этом нет необходимости, поскольку списки занимают незначительную долю быстрее, создание кортежа требует минимальных затрат, и (что важно) ваши строки будут разбиты на последовательности переменного размера, которые концептуально являются списками.

Скорость может быть улучшена только спуском до уровня C / Cython, я думаю; str.split трудно превзойти, так как он написан на C, а списочные выражения - AFAIK - самая быстрая конструкция цикла в Python.

Что еще более важно, это очень понятный и Pythonic код. Я бы не пытался оптимизировать это, кроме бита генератора.

...