Простой Python. Современный стиль программирования (Любанович) - страница 69

>>>> sum(range(1, 101))

>5050

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

Если вы хотите создать потенциально большую последовательность и ее код слишком велик для того, чтобы создать включение генератора, напишите функцию генератора. Это обычная функция, но она возвращает значение с помощью выражения yield, а не return. Напишем собственную функцию range():

>>>> def my_range(first=0, last=10, step=1):

>…·····number = first

>…·····while number < last:

>…·········yield number

>…·········number += step

>…

Это нормальная функция:

>>>> my_range

>

И она возвращает объект генератора:

>>>> ranger = my_range(1, 5)

>>>> ranger

>

Мы можем проитерировать по этому объекту генератора:

>>>> for x in ranger:

>…·····print(x)

>…

>1

>2

>3

>4

Декораторы

Иногда вам нужно модифицировать существующую функцию, не меняя при этом ее исходный код. Зачастую нужно добавить выражение для отладки, чтобы посмотреть, какие аргументы были туда переданы.

Декоратор — это функция, которая принимает одну функцию в качестве аргумента и возвращает другую функцию. Мы используем следующие приемы из нашего арсенала:

• *args и **kwargs;

• внутренние функции;

• функции в качестве аргументов.

Функция document_it() определяет декоратор, который:

• выведет имя функции и значение переданных в нее аргументов;

• запустит функцию с полученными аргументами;

• выведет результат;

• вернет модифицированную функцию, готовую для использования.

Код будет выглядеть так:

>>>> def document_it(func):

>…·····def new_function(*args, **kwargs):

>…·········print('Running function:', func.__name__)

>…·········print('Positional arguments:', args)

>…·········print('Keyword arguments:', kwargs)

>…·········result = func(*args, **kwargs)

>…·········print('Result:', result)

>…·········return result

>…·····return new_function

Независимо от того, какую функцию func вы передадите document_it(), вы получите новую функцию, которая содержит дополнительные выражения, добавляемые document_it(). Декоратор не обязательно должен запускать код функции func, но функция document_it() вызовет часть func, поэтому вы получите результат работы функции func, а также дополнительные данные:

>>>> def add_ints(a, b):

>…····return a + b

>…

>>>> add_ints(3, 5)

>8

>>>> cooler_add_ints = document_it(add_ints)··# мануальное присваивание декоратора