Когда следует использовать выражения генератора, а когда - понимание списков в Python?
# Generator expression (x*2for x inrange(256))
# List comprehension [x*2for x inrange(256)]
Переведено автоматически
Ответ 1
Ответ Джона хорош (понимание списков лучше, когда вы хотите повторить что-то несколько раз). Однако также стоит отметить, что вам следует использовать список, если вы хотите использовать любой из методов списка. Например, следующий код не будет работать:
defgen(): return (something for something in get_some_stuff())
print gen()[:2] # generators don't support indexing or slicing print [5,6] + gen() # generators can't be added to lists
В принципе, используйте выражение генератора, если все, что вы делаете, это повторяете один раз. Если вы хотите сохранить и использовать сгенерированные результаты, то вам, вероятно, лучше использовать понимание списка.
Поскольку производительность является наиболее распространенной причиной предпочесть одно другому, мой совет - не беспокоиться об этом и просто выбрать одно; если вы обнаружите, что ваша программа работает слишком медленно, тогда и только тогда вам следует вернуться и побеспокоиться о настройке вашего кода.
Ответ 2
Повторение выражения генератора или понимания списка приведет к тому же результату. Однако понимание списка сначала создаст весь список в памяти, в то время как выражение генератора создаст элементы "на лету", поэтому вы можете использовать его для очень больших (а также бесконечных!) последовательностей.
Ответ 3
Используйте понимание списка, когда результат необходимо повторить несколько раз или когда скорость имеет первостепенное значение. Используйте выражения генератора, диапазон которых велик или бесконечен.
Важным моментом является то, что понимание списка создает новый список. Генератор создает итеративный объект, который будет "фильтровать" исходный материал на лету по мере использования битов.
Представьте, что у вас есть файл журнала объемом 2 ТБ под названием "hugefile.txt", и вам нужно указать содержимое и длину всех строк, начинающихся со слова "ЗАПИСЬ".
Итак, вы пытаетесь начать с написания понимания списка:
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 итератора, который, в свою очередь, считывает файл.
Таким образом, вместо того, чтобы "передавать" данные в вашу функцию вывода в виде полностью заполненного списка, вы предоставляете функции вывода возможность "извлекать" данные только тогда, когда это необходимо. В нашем случае это намного эффективнее, но не так гибко. Генераторы - это односторонний способ, один проход; данные из файла журнала, который мы прочитали, немедленно отбрасываются, поэтому мы не можем вернуться к предыдущей строке. С другой стороны, нам не нужно беспокоиться о сохранении данных, как только мы закончим с ними.