Статьи

Введение в генераторы Python

Генераторы облегчают создание итераций в Python и, в свою очередь, пишут меньше кода. Это руководство познакомит вас с генераторами Python, их преимуществами и тем, как они работают.

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

Оператор yield обычно останавливает функцию и сохраняет локальное состояние, чтобы его можно было возобновить с того места, где оно было остановлено. Функции генератора могут иметь один или несколько операторов yield .

Генератор также является итератором, но что такое итератор? Прежде чем мы углубимся в детали генераторов, я думаю, что важно знать, что такое итераторы, потому что они составляют неотъемлемую часть этого обсуждения.

Итератор Python — это просто класс, который определяет __iter__() . Большинство объектов Python являются итеративными, что означает, что вы можете перебирать каждый элемент в объектах. Примеры итераций в Python включают строки, списки, кортежи, словари и диапазоны.

Давайте рассмотрим пример ниже, в котором мы перебираем список цветов:

1
2
3
4
5
colors= [“red”,”blue”,”yellow”]
 
def my_funct():
    for color in colors:
        print color

За кулисами оператор for вызовет iter() для объекта списка. Затем функция вернет объект итератора, который определяет метод __next__() , который затем будет обращаться к каждому цвету, по одному за раз. Когда не осталось больше цветов, __next__ stopIteration исключение stopIteration , которое, в свою очередь, будет информировать цикл for о завершении.

1
2
3
4
5
6
7
8
d = {‘x’: 10, ‘y’: 20, ‘z’: 30}
for k,v in d.items():
    print k, v
 
#result
# y 20
# x 10
# z 30
1
2
3
4
5
6
import csv
 
with open(‘file.csv’, newline=») as File:
    reader = csv.reader(File)
    for row in reader:
        yield row
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
my_string = ‘Generators’
for string in my_string:
    print (string)
     
#result
 
# G
# e
# n
# e
# r
# a
# t
# o
# r
# s

Давайте обсудим некоторые преимущества использования генераторов по сравнению с итераторами:

Построение итератора в Python потребует от вас реализации класса с помощью __iter__() и __next__() а также позаботится о любых ошибках, которые могут вызвать ошибку stopIteration .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
class Reverse:
   «»»Iterator for looping over a sequence backwards.»»»
   def __init__(self, data):
       self.data = data
       self.index = len(data)
 
   def __iter__(self):
       return self
 
   def __next__(self):
       if self.index == 0:
           raise StopIteration
       self.index = self.index — 1
       return self.data[self.index]

Как вы можете видеть выше, реализация очень длинная. Все это бремя автоматически обрабатывается генераторами.

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

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

Создать генератор очень просто. Все, что вам нужно сделать, это написать обычную функцию, но с оператором yield вместо оператора return , как показано ниже.

1
2
def gen_function():
   yield «python»

В то время как оператор return полностью завершает функцию, yield просто приостанавливает функцию до тех пор, пока она не будет снова вызвана методом next() .

Например, в приведенной ниже программе используются операторы yield и next() .

01
02
03
04
05
06
07
08
09
10
def myGenerator(l):
     total = 1
     for n in l:
       yield total
       total += n
      
newGenerator = myGenerator([10,3])
 
print(next(newGenerator))
print(next(newGenerator))

Посмотрим, как работают генераторы. Рассмотрим пример ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
# generator_example.py
 
def myGenerator(l):
     total = 0
     for n in l:
       total += n
       yield total
       
      
newGenerator = myGenerator([10,20,30])
 
print(next(newGenerator))
print(next(newGenerator))
print(next(newGenerator))
  

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

Затем мы newGenerator экземпляр newGenerator и вызываем метод next() для него. Это будет запускать код до тех пор, пока не будет получено первое значение total , которое в этом случае будет равно 0 Затем функция сохраняет значение общей переменной до следующего вызова функции. В отличие от обычного оператора return , который будет возвращать все значения одновременно, генератор будет продолжать с того места, где он остановился.

Ниже приведены остальные последующие значения.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
# generator_example.py
 
def myGenerator(l):
     total = 0
     for n in l:
       yield total
       total += n
       
      
newGenerator = myGenerator([10,20,30])
 
print(next(newGenerator))
print(next(newGenerator))
print(next(newGenerator))
   
# result
 
# 0
# 10
# 30

Если вы попытаетесь вызвать функцию после завершения цикла, вы получите ошибку StopIteration .

StopIteration next() StopIteration чтобы сигнализировать, что итератор не производит никаких других элементов.

1
2
3
4
5
6
7
0
10
30
 
Traceback (most recent call last):
  File «python», line 15, in <module>
StopIterationNormal function

В этом примере мы покажем, как использовать несколько операторов yield в функции.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
# colors.py
 
def colors():
  yield «red»
  yield «blue»
  yield «green»
   
next_color =colors()
    
print(next(next_color))
print(next(next_color))
print(next(next_color))
 
# result
 
# red
# blue
# green

В то время как нормальная функция возвращает все значения, когда функция вызывается, генератор ждет, пока метод next() будет вызван снова. Когда вызывается next() , функция colors возобновляется с того места, где она остановилась.

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

Кроме того, не забудьте посмотреть, что у нас есть в наличии для продажи и для изучения на Envato Market , и не стесняйтесь задавать любые вопросы и предоставлять ценные отзывы, используя канал ниже.

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