У меня есть такой текстовый файл:
11
2
3
4
11
111
Используя Python 2.7, я хочу превратить его в список списков строк, где разрывы строк разделяют элементы во внутреннем списке, а пустые строки — во внешнем списке. Вот так:
[["11","2","3","4"],["11"],["111"]]
И для этой цели я написал функцию-генератор, которая будет выдавать внутренние списки по одному после передачи объекта открытого файла :
def readParag(fileObj):
currentParag = []
for line in fileObj:
stripped = line.rstrip()
if len(stripped) > 0: currentParag.append(stripped)
elif len(currentParag) > 0:
yield currentParag
currentParag = []
. Это прекрасно работает, и я могу вызывать это из понимания списка, получая желаемый результат. Однако впоследствии мне пришло в голову, что я мог бы сделать то же самое более лаконично, используяitertools.takewhile
(с целью переписать функцию генератора как выражение генератора, но пока оставим это ). Это то, что я пробовал:
from itertools import takewhile
def readParag(fileObj):
yield [ln.rstrip() for ln in takewhile(lambda line: line != "\n", fileObj)]
В этом случае результирующий генератор дает только один результат (ожидаемый первый, т.е.["11","2","3","4"]
). Я надеялся, что повторный вызов его метода next
заставит его снова вычислить takewhile(lambda line: line != "\n", fileObj)
в оставшейся части файла, что приведет к получению другого списка. Но нет :Вместо этого я получил StopIteration
. Поэтому я предположил, что выражение take while
вычислялось только один раз, во время создания объекта-генератора, а не каждый раз, когда я вызывал метод next
результирующего объекта-генератора.
Это предположение заставило меня задуматься, что произойдет, если я снова вызову функцию генератора. В результате был создан новый объект-генератор, который также дал один результат (вместо ожидаемого второго, то есть["11"]
)перед тем, как бросить StopIteration
в меня. Таким образом, написание этого как функции-генератора эффективно дает тот же результат, как если бы я написал это как обычную функцию и return
редактировал список вместо yield
его.
Думаю, я мог бы решить эту проблему, создав собственный класс для использования вместо генератора (, как в ответе Джона Милликина на этот вопрос). Но дело в том, что я надеялся написать что-то более лаконичное, чем моя исходная функция генератора (возможно, даже выражение генератора ). Может кто-нибудь сказать мне, что я делаю неправильно, и как это исправить?