Мне нравится идея функции генератора iWerner. Одно небольшое изменение его кода, и он делает то, о чем спрашивал вопрос.
def readlines(filename):
f = open(filename)
# discard first lines that start with '#'
for line in f:
if not line.lstrip().startswith("#"):
break
yield line
for line in f:
yield line
и использовать его как
for line in readlines("data.txt"):
# do things
pass
Но вот другой подход. Это почти очень просто. Идея состоит в том, что мы открываем файл и получаем файл-объект, который мы можем использовать в качестве итератора. Затем мы вытягиваем строки, которые не хотим выходить из итератора, и просто возвращаем итератор. Это было бы идеально, если бы мы всегда знали, сколько строк пропустить. Проблема здесь в том, что мы не знаем, сколько строк нам нужно пропустить; нам просто нужно тянуть линии и смотреть на них. И нет способа вернуть строку в итератор, как только мы потянем его.
Итак: откройте итератор, вытащите линии и подсчитайте, сколько имеет символ «#»; затем используйте метод .seek()
для перемотки назад файла, снова верните правильный номер и верните итератор.
Одна вещь, которая мне нравится в этом вопросе: вы возвращаете фактический объект файла со всеми его методами; вы можете использовать его вместо open()
, и он будет работать во всех случаях. Я переименовал функцию в open_my_text()
, чтобы отразить это.
def open_my_text(filename):
f = open(filename, "rt")
# count number of lines that start with '#'
count = 0
for line in f:
if not line.lstrip().startswith("#"):
break
count += 1
# rewind file, and discard lines counted above
f.seek(0)
for _ in range(count):
f.readline()
# return file object with comment lines pre-skipped
return f
Вместо f.readline()
я мог бы использовать f.next()
(для Python 2.x) или next(f)
(для Python 3.x), но я хотел написать его так, чтобы было переносимым на любой Python.
EDIT: Хорошо, я знаю, что никто не заботится и я "не получаю никаких upvotes для этого, но я переписал мой ответ в последний раз, чтобы сделать его более изящным
Вы не можете поставить. вернитесь в итератор, но вы можете открыть файл дважды и получить два итератора, учитывая способ работы кэширования файлов, второй итератор почти свободен. Если мы представим файл с мегабайтом строк «#» наверху , эта версия будет значительно превосходить предыдущую версию, которая вызывает f.seek(0)
.
def open_my_text(filename):
# open the same file twice to get two file objects
# (We are opening the file read-only so this is safe.)
ftemp = open(filename, "rt")
f = open(filename, "rt")
# use ftemp to look at lines, then discard from f
for line in ftemp:
if not line.lstrip().startswith("#"):
break
f.readline()
# return file object with comment lines pre-skipped
return f
Эта версия гораздо лучше, чем в предыдущей версии, и она по-прежнему возвращается полный файловый объект со всеми его методами.
http://stackoverflow.com/questions/1706198/python-how-to-ignore-comment-lines-when-reading-in-a-file/1706204#1706204 – ghostdog74
«Короче» не обязательно «Pythonic» , То, что у вас есть, очень аккуратно, ясно и само собой разумеется. Свертывание его в неясное однострочное не всегда способствует питоничности. Насколько мне нравится itertools, иногда его функциональный подход заставляет меня перестать почесывать голову. Pythonic-код должен требовать небольшого количества царапин на голове. Если бы мне пришлось голосовать за альтернативную форму и называть ее более Pythonic, это было бы решение о понимании списка Джима Денниса. – PaulMcG