Есть ли какие-то преимущества не генераторов итераторов по сравнению с генераторами в Python? - PullRequest
0 голосов
/ 13 октября 2019

В приведенном ниже коде i1 является итератором.

def sq(x):

    y = []

    for i in x:
        y.append(i**2)

    return y

l1 = range(5)
s1 = sq(l1)
i1 = iter(s1)

Я могу написать генератор для той же операции возведения в квадрат. В приведенном ниже коде g1 является генератором.

def sqg(x):

    for i in x:

        yield i**2

g1 = sqg(l1)

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

Есть ли какие-либо преимущества в использовании i1 перед g1?

Ответы [ 2 ]

1 голос
/ 13 октября 2019

Существуют преимущества создания списка s1 перед генератором - он имеет определенную длину, вы можете индексировать и разрезать его, и вы можете просматривать его несколько раз, не создавая его заново. Возможно, вы не считаете их преимуществами итератора, не являющегося генератором.

Другое отличие состоит в том, что итератор на основе списка включает в себя выполнение всей работы заранее, а затем кэширование результатов, в то время как генератор это делает. работа по шагам за раз. Если задача обработки является ресурсоемкой, то подход с использованием списка вызовет первоначальную паузу при создании списка, а затем будет выполняться быстрее (поскольку вам нужно только извлечь результаты из памяти; также учтите, что результаты могут быть кэшированы в файле, например). Генераторный подход не будет иметь начальной паузы, но будет работать медленнее, поскольку генерирует каждый результат.

1 голос
/ 13 октября 2019

Когда вы звоните sq(l1), внутри sq, список y заполняется. Это потребляет память, размер которой пропорционален размеру x после исчерпания.

Во втором случае, когда вы звоните sqg(l1), sqg не имеет внутреннего списка, используемого для хранения результатов. Он напрямую выдает вычисленные значения, что делает потребляемую память постоянной и независимой от размера x после исчерпания.

Что касается преимуществ итераторов, не являющихся генераторами, по сравнению с генераторами, я не думаю, что есть преимущества в производительности, но могут быть и структурные преимущества. Генератор (тип итератора, как вы заметили) определяется как итератор, возвращаемый вызовом функции с yield инструкциями внутри. Это означает, что вы не можете добавлять какие-либо дополнительные методы, которые могут быть вызваны к объекту, представляющему генератор, поскольку этот специальный тип итератора предоставляется вам неявно.

С другой стороны, итератор имеет более свободное определение:объект с методом __next__ и методом __iter__, возвращающим self. Вы можете создать класс Squares, который соответствует предыдущему критерию для итератора, и для того, чтобы получить экземпляр для этого итератора, вам придется явно создать экземпляр Squares. Поскольку у вас есть контроль над атрибутами итератора , возвращенными вам, вы можете добавить методы экземпляра, возвращающие внутреннее состояние этого итератора, которые не выражаются через __next__, тогда как с генератором вы заблокированы вобъект генератора, предоставленный вам неявно. Часто генератор будет выполнять эту работу, но иногда вам нужно использовать итератор, не связанный с генератором, чтобы получить контроль, который вам необходим, за счет функциональности, предоставляемой __next__.

В этом конкретном случае я не верювам нужен явный контроль, предоставленный вам с помощью итератора без генератора, поэтому было бы лучше использовать генератор.

...