>>>> 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)··# мануальное присваивание декоратора