Чтение n строк из файла (но не всех) в Python - PullRequest
2 голосов
/ 03 декабря 2010

Как прочитать n строк из файла, а не только одну при переборе по нему? У меня есть файл с четко определенной структурой, и я хотел бы сделать что-то вроде этого:

for line1, line2, line3 in file:
    do_something(line1)
    do_something_different(line2)
    do_something_else(line3)

но это не работает:

ValueError: слишком много значений для распаковки

Пока я делаю это:

for line in file:
    do_someting(line)
    newline = file.readline()
    do_something_else(newline)
    newline = file.readline()
    do_something_different(newline)
... etc.

- отстой, потому что я пишу бесконечные 'newline = file.readline()', которые загромождают код. Есть ли умный способ сделать это? (Я действительно хочу избежать чтения всего файла сразу, потому что он огромен)

Ответы [ 11 ]

4 голосов
/ 03 декабря 2010

По сути, ваш file является итератором, который выдает ваш файл по одной строке за раз.Это превращает вашу проблему в то, как вы получаете несколько элементов одновременно от итератора.Решение этого вопроса дано в этом вопросе .Обратите внимание, что функция islice находится в модуле itertools, поэтому вам придется импортировать ее оттуда.

3 голосов
/ 03 декабря 2010

Если это xml, почему бы просто не использовать lxml?

2 голосов
/ 04 декабря 2010

itertools на помощь:

import itertools
def grouper(n, iterable, fillvalue=None):
    "grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
    args = [iter(iterable)] * n
    return itertools.izip_longest(fillvalue=fillvalue, *args)


fobj= open(yourfile, "r")
for line1, line2, line3 in grouper(3, fobj):
    pass
2 голосов
/ 03 декабря 2010

Вы можете использовать вспомогательную функцию следующим образом:

def readnlines(f, n):
    lines = []
    for x in range(0, n):
        lines.append(f.readline())
    return lines

Тогда вы можете сделать что-то, что вы хотите:

while True:
    line1, line2, line3 = readnlines(file, 3)
    do_stuff(line1)
    do_stuff(line2)
    do_stuff(line3)

При этом, если вы используете файлы XML,вы, вероятно, будете счастливее в долгосрочной перспективе, если будете использовать настоящий xml-парсер ...

1 голос
/ 03 декабря 2010

for i in file создает str, поэтому вы не можете просто сделать for i, j, k in file и прочитать его партиями по три (попробуйте a, b, c = 'bar' и a, b, c = 'too many characters' и посмотрите на значения a, b и c, чтобывыяснить, почему вы получаете «слишком много значений для распаковки»).

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

for line in file_handle:
    do_something(line)
    if some_condition:
        break  # Don't want to read anything else

(Кроме того, не используйте file в качестве имени переменной, вы затеняете встроенную функцию.)

0 голосов
/ 03 декабря 2010

Это можно сделать с умным использованием функции zip.Это коротко, но немного вуду, на мой вкус (трудно понять, как это работает).Он обрезает все строки в конце, которые не заполняют группу, что может быть хорошим или плохим в зависимости от того, что вы делаете.Если вам нужны последние строки, itertools.izip_longest может помочь.

zip(*[iter(inputfile)] * 3)

Делая это более явно и гибко, это модификация решения Матса Экберга:

def groupsoflines(f, n):
    while True:
        group = []
        for i in range(n):
            try:
                group.append(next(f))
            except StopIteration:
                if group:
                    tofill = n - len(group)
                    yield group + [None] * tofill
                return
        yield group

for line1, line2, line3 in groupsoflines(inputfile, 3):
    ...

NBЕсли в середине группы не хватает строк, они заполнят пробелы None, так что вы все равно сможете распаковать их.Таким образом, если число строк в вашем файле не кратно трем, вам нужно проверить, являются ли line2 и line3 None.

0 голосов
/ 03 декабря 2010

Звучит так, будто вы пытаетесь читать с диска параллельно ... это действительно сложно сделать.Все решения, предоставленные вам, являются реалистичными и законными.Вы не должны позволять чему-то отталкивать вас только потому, что код «выглядит ужасно».Самое главное, насколько это эффективно / действенно, тогда, если код грязный, вы можете привести его в порядок, но не ищите совершенно новый способ что-то сделать, потому что вам не нравится, как это сделать одним способом.выглядит как в коде.

Что касается нехватки памяти, вы можете проверить pickle .

0 голосов
/ 03 декабря 2010

почему ты не можешь просто сделать:

ctr = 0

для строки в файле:

  if ctr == 0:

     ....

  elif ctr == 1:

     ....

  ctr = ctr + 1

если вы сочтете конструкцию if / elif безобразной, вы можете просто создать хеш-таблицу или список указателей на функции и затем выполнить:

для строки в файле:

   function_list[ctr]()

или что-то подобное

0 голосов
/ 03 декабря 2010

Если вы хотите иметь возможность использовать эти данные снова и снова, один из подходов может быть следующим:

lines = []
for line in file_handle:
    lines.append(line)

Это даст вам список строк, к которым вы затем сможете получить доступпо индексуКроме того, когда вы говорите ОГРОМНЫЙ файл, его размер, скорее всего, тривиален, потому что python может очень быстро обрабатывать тысячи строк.

0 голосов
/ 03 декабря 2010

Знаете ли вы что-нибудь о длине строк / формате данных? Если это так, вы можете прочитать первые n байтов (скажем, 80 * 3) и f.read (240) .split ("\ n") [0: 3].

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