Важным моментом является то, что понимание списка создает новый список. Генератор создает итеративный объект, который будет «фильтровать» исходный материал на лету, когда вы используете биты.
Представьте, что у вас есть файл журнала объемом 2 ТБ, называемый "принц", и вам нужно содержимое и длина для всех строк, начинающихся со слова "ВХОД".
Итак, попробуйте начать с написания списка:
logfile = open("hugefile.txt","r")
entry_lines = [(line,len(line)) for line in logfile if line.startswith("ENTRY")]
Это затирает весь файл, обрабатывает каждую строку и сохраняет совпадающие строки в вашем массиве. Следовательно, этот массив может содержать до 2 ТБ контента. Это много оперативной памяти, и, вероятно, не практично для ваших целей.
Поэтому вместо этого мы можем использовать генератор, чтобы применить «фильтр» к нашему контенту. На самом деле данные не читаются, пока мы не начнем итерацию по результату.
logfile = open("hugefile.txt","r")
entry_lines = ((line,len(line)) for line in logfile if line.startswith("ENTRY"))
Из нашего файла еще не было прочитано ни одной строки. На самом деле, скажем, мы хотим отфильтровать наш результат еще дальше:
long_entries = ((line,length) for (line,length) in entry_lines if length > 80)
Пока ничего не прочитано, но мы указали два генератора, которые будут работать с нашими данными так, как мы хотим.
Давайте запишем наши отфильтрованные строки в другой файл:
outfile = open("filtered.txt","a")
for entry,length in long_entries:
outfile.write(entry)
Теперь мы читаем входной файл. Поскольку наш for
цикл продолжает запрашивать дополнительные строки, long_entries
генератор запрашивает строки из entry_lines
генератора, возвращая только те, длина которых превышает 80 символов. И, в свою очередь, entry_lines
генератор запрашивает строки (отфильтрованные как указано) отlogfile
итератора, который, в свою очередь, читает файл.
Таким образом, вместо того, чтобы «выталкивать» данные в вашу функцию вывода в виде полностью заполненного списка, вы даете функции вывода способ «извлекать» данные только тогда, когда это необходимо. В нашем случае это гораздо эффективнее, но не так гибко. Генераторы один путь, один проход; данные из файла журнала, который мы прочитали, немедленно удаляются, поэтому мы не можем вернуться к предыдущей строке. С другой стороны, нам не нужно беспокоиться о сохранении данных, как только мы закончим с ними.
[exp for x in iter]
быть просто сахар дляlist((exp for x in iter))
? или есть разница в исполнении?