Я хочу обрабатывать много файлов, как если бы они были одним файлом. Каков правильный питонический способ взять [filenames] => [file objects] => [lines] с генераторами/не считывать весь файл в память?Какой самый pythonic способ перебрать все строки из нескольких файлов?
Мы все знаем, что правильный способ открыть файл:
with open("auth.log", "rb") as f:
print sum(f.readlines())
И мы знаем, что правильный способ связать несколько итераторов/генераторов в один длинный один:
>>> list(itertools.chain(range(3), range(3)))
[0, 1, 2, 0, 1, 2]
но как я связать несколько файлов вместе и сохранить менеджеров контекста?
with open("auth.log", "rb") as f0:
with open("auth.log.1", "rb") as f1:
for line in itertools.chain(f0, f1):
do_stuff_with(line)
# f1 is now closed
# f0 is now closed
# gross
я мог игнорировать менеджеров контекста и сделать что-то вроде этого, но он не чувствует себя хорошо:
files = itertools.chain(*(open(f, "rb") for f in file_names))
for line in files:
do_stuff_with(line)
Или это вроде того, что Async IO - PEP 3156 для и я буду только ждать элегантный синтаксис позже?
Также обратите внимание, что 'files = itertools.chain (* (open (f," rb ") для f в file_names))' в этом контексте определенно нехорошо. распаковка кортежа приводит к тому, что все ваши файлы будут открыты до того, как вы действительно войдете в конструктор 'chain'. Вам лучше с 'itertools.chain.from_iterable (open (fname, 'r') для fname в именах файлов))' - На самом деле это классическая причина, по которой метод класса 'from_iterable' должен существовать в первом место :). – mgilson
@mgilson понятия не имел, 'from_iterable' был чем-то! Я рад, что мой usecase - пример учебника, почему он полезен. Я пытался выяснить, как правильно заставить ленивую оценку работать без вложенных циклов. Благодаря! –
Обратите внимание, что даже 'from_iterable' не гарантирует, что все ваши файлы будут закрыты, когда вы закончите итерацию по нему, потому что вы никогда не знаете, когда будет запущен' __del__' (хотя я уверен, что они будут в Cpython) ... – mgilson