Вопрос-Ответ

Generator expressions vs. list comprehensions

Выражения генератора против понимания списков

Когда следует использовать выражения генератора, а когда - понимание списков в Python?

# Generator expression
(x*2 for x in range(256))

# List comprehension
[x*2 for x in range(256)]
Переведено автоматически
Ответ 1

Ответ Джона хорош (понимание списков лучше, когда вы хотите повторить что-то несколько раз). Однако также стоит отметить, что вам следует использовать список, если вы хотите использовать любой из методов списка. Например, следующий код не будет работать:

def gen():
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

Используйте понимание списка, когда результат необходимо повторить несколько раз или когда скорость имеет первостепенное значение. Используйте выражения генератора, диапазон которых велик или бесконечен.

Смотрите Выражения генератора и понимание списков для получения дополнительной информации.

Ответ 4

Важным моментом является то, что понимание списка создает новый список. Генератор создает итеративный объект, который будет "фильтровать" исходный материал на лету по мере использования битов.

Представьте, что у вас есть файл журнала объемом 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 итератора, который, в свою очередь, считывает файл.

Таким образом, вместо того, чтобы "передавать" данные в вашу функцию вывода в виде полностью заполненного списка, вы предоставляете функции вывода возможность "извлекать" данные только тогда, когда это необходимо. В нашем случае это намного эффективнее, но не так гибко. Генераторы - это односторонний способ, один проход; данные из файла журнала, который мы прочитали, немедленно отбрасываются, поэтому мы не можем вернуться к предыдущей строке. С другой стороны, нам не нужно беспокоиться о сохранении данных, как только мы закончим с ними.

2023-07-17 13:58 python