Если есть функция, которая возвращает последовательность, то скорее всего, ее можно превратить в функцию-генератор.
Например есть функция, которая перебирает символы строки, пока не будет достигнуто их заданное количество stop_item
, значение stop_item=0
будет возвращать список всех символов строки:
def stop_iter(iteration, stop_item=0): elements = [] for n, item in enumerate(iteration, 1): elements.append(item) if n == stop_item: break return elements
Эта функция принимает итерируемый объект (в данном случае строку) и возвращает по очереди элементы этого объекта, включая элемент под номером stop_item
:
>>> string = 'абракадабра' >>> results = stop_iter(string, 7) >>> results # ['а', 'б', 'р', 'а', 'к', 'а', 'д']
Представленная выше функция создает итоговый список в момент её вызова, а затем возвращает его. Но что, если генерируемый список очень большой и есть требование, не забивать оперативную память. В этом случае функция должна возвращать "ленивую" итерацию вместо результирующего списка.
Как можно вернуть итерируемый объект, пока не начнется перебор элементов в цикле? Для этого необходимо использовать оператор yield
. Оператор yield
- это то, что превращает функцию в функцию генератора.
Момент вызовов добавления нового элемента elements.append(item)
в конец итогового списка elements
необходимо заменить оператором yield item, а затем полностью удалить из функции упоминание об списке elements
:
Для более ясного понимания, какие преобразования выполнены, строки, которые необходимо удалить оставим закомментированными.
def stop_iter(iteration, stop_item=0): # elements = [] for n, item in enumerate(iteration, 1): # elements.append(item) yield item if n == stop_item: break # return elements
Теперь, если вызвать функцию stop_iter()
, она на самом деле не запускает код, расположенный внутри неё. Вместо этого функция stop_iter()
возвращает объект-генератор, который будет работать, пока его перебирают.
>>> string = 'абракадабра' >>> results = stop_iter(string, 7) >>> results # <generator object stop_iter at 0x7f1508dced60> >>> next(results) # 'а' >>> next(results) # 'б' >>> list(results) # ['р', 'а', 'к', 'а', 'д'] # не забываем, что генераторы конечны. >>> list(results) # [] >>> next(results) # Traceback (most recent call last): # File "<stdin>", line 1, in <module> # StopIteration