вопрос стиля python вокруг чтения маленьких файлов - PullRequest
3 голосов
/ 02 февраля 2010

Какой самый питонный способ чтения в именованном файле - обрезать строки, которые либо пусты, либо содержат только пробелы, либо имеют # в качестве первого символа, а затем обрабатывают оставшиеся строки? Предположим, все это легко помещается в памяти.

Примечание: это не сложно сделать - я спрашиваю о наиболее питоническом способе. Я много писал на Ruby и Java и потерял самообладание.

Вот соломинка:

file_lines = [line.strip() for line in open(config_file, 'r').readlines() if len(line.strip()) > 0]
for line in file_lines:
  if line[0] == '#':
    continue
  # Do whatever with line here.

Меня интересует краткость, но не за счет того, что мне трудно читать.

Ответы [ 8 ]

5 голосов
/ 02 февраля 2010

Генераторы идеально подходят для подобных задач. Они читабельны, поддерживают идеальное разделение задач и эффективны в использовании памяти и времени.

def RemoveComments(lines):
    for line in lines:
        if not line.strip().startswith('#'):
            yield line

def RemoveBlankLines(lines):
    for line in lines:
        if line.strip():
            yield line

Теперь примените их к вашему файлу:

filehandle = open('myfile', 'r')
for line in RemoveComments(RemoveBlankLines(filehandle)):
    Process(line)

В этом случае довольно ясно, что два генератора можно объединить в один, но я оставил их отдельно, чтобы продемонстрировать их совместимость.

3 голосов
/ 02 февраля 2010
lines = [r for r in open(thefile) if not r.isspace() and r[0] != '#']

Метод строк .isspace() - безусловно, лучший способ проверить, является ли строка полностью пробелом - нет необходимости в искажениях, таких как len(r.strip()) == 0 (ech; -).

2 голосов
/ 02 февраля 2010
for line in open("file"):
    sline=line.strip()
    if sline and not sline[0]=="#" :
       print line.strip()

выход

$ cat file
one
#
  #

two

three
$ ./python.py
one
two
three
1 голос
/ 02 февраля 2010

Мне нравится мышление Пола Хэнкина, но я бы сделал это по-другому:

from itertools import ifilter, ifilterfalse, imap

with open(r'c:\temp\testfile.txt', 'rb') as f:
    s1 = ifilterfalse(str.isspace, f)
    s2 = ifilter(lambda x: not x.startswith('#'), s1)
    s3 = imap(str.rstrip, s2)
    print "\n".join(s3)

Я бы, вероятно, сделал бы это только так, вместо того, чтобы использовать некоторые из более очевидных подходов, предложенных здесь, если бы меня беспокоило использование памяти. И я мог бы определить iscomment функцию для устранения лямбды.

1 голос
/ 02 февраля 2010

Это соответствует описанию, т.е.

пустые линии, содержать только пробелы или иметь # как сначала символ, а затем процесс остальные строки

Таким образом, строки, начинающиеся или оканчивающиеся пробелами, пропускаются без ограничений

with open("config_file","r") as fp:
    data = (line for line in fp if line.strip() and not line.startswith("#"))
    for item in data:
        print repr(item)
1 голос
/ 02 февраля 2010

Я бы использовал это:

processed = [process(line.strip())
             for line in open(config_file, 'r')
             if line.strip() and not line.strip().startswith('#')]

Единственное уродство, которое я вижу здесь, это все повторяющиеся раздевания. Избавление от него немного усложняет функцию:

processed = [process(line)
             for line in (line.strip() for line in open(config_file, 'r'))
             if line and not line.startswith('#')]
0 голосов
/ 02 февраля 2010

Используя немного более новые идиомы (или с Python 2.5 from __future__ import with), вы можете сделать это, что имеет преимущество в том, что очистка безопасна, но довольно лаконична.

with file('file.txt') as fp:
    for line in fp:
        line = line.strip()
        if not line or line[0] == '#':
            continue

        # rest of processing here

Обратите внимание, что удаление строки в первую очередь означает, что проверка на "#" фактически отклонит строки с этим как первый непустой , а не просто как первый символ. Достаточно легко изменить, если вы строго относитесь к этому.

0 голосов
/ 02 февраля 2010

Файл небольшой, поэтому производительность не является проблемой.Я пойду для ясности, чем краткость:

fp = open('file.txt')
for line in fp:
    line = line.strip()
    if line and not line.startswith('#'):
        # process
fp.close()

Если вы хотите, вы можете заключить это в функцию.

...