РЕКОМЕНДУЕМ - ИНВЕСТИРОВАНИЕ В ИНТЕРНЕТЕ - ОТ 0,1 ДО 2 % В ДЕНЬ, ПРОВЕРЕНО.


При условии регистрации по этой ссылке, рекомендации и консультации для Вас бесплатны danilclub@mail.ru



Е-книги
Практическое пособие по созданию WEB-сайтов для начинающих
Самоучитель по Webдизайну
Самоучитель по интернет- программированию
Самоучитель по работе в Internet
Статьи
Спам
Интернет
Железо
Мобилы
Безопасность
Сетевые технологии
Программирование
Вебдизайн
Вебстроительство
Скрипты
Раскрутка
Flash
Photoshop
Windows, Soft
Linux
Описание игр
Другие
Бизнес-идеи
Электроника и техника
Малый бизнес
Интернет-бизнес
Моя ферма
Раскрутка сайтов
Технологии бизнеса
Руководства
Юмор
Введение
Вовочка
Законы Мерфи
КВН
Компъютерные
Нигеры
Поэзия
Пор-чик Ржевский
Тёща
Чукча
Школа
Штирлиц
Разные
Избранные
Пособия
Смешные истории


Rambler's Top100
Rambler's Top100

Купить подоконник в Киеве. попасть на биржу статей. Профессиональная разработка и продвижение веб-сайтов в г. Алматы, Казахстан.
купить постельное белье. Сайт для Незнаек

Итераторы и простые генераторы

В Python 2.2 появилась новая конструкция со своим ключевым словом. Эта конструкция - генератор, а ключевое слово - yield. Хотя генераторы позволяют реализовать новые, мощные и оригинальные идеи, все же не так-топросто понять, как они работают. Эта статья - попытка ненавязчивого объяснения этой конструкции, равно как связанного с ней понятия итераторов.

Что такое Python?

Python - свободно доступный, интерпретируемый язык программирования высокого уровня, разработанный Гвидо ван Россумом (Guido vanRossum). Он объединяет ясный синтаксис с мощной (но необязательно) объектно-ориентированной семантикой. Python может быть установлен на любой платформе и обеспечивает прекрасную совместимость при переходе с одной платформы на другую.

Введение

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

И хотя то, что предлагает Python 2.2, не настолько умопомрачительно, как, например, полные продолжения и микронити, представленныев Stackless Python, генераторы и итераторы действительно могут кое-что, что выделяет их среди традиционных функций и классов.

Давайте рассмотрим сначала итераторы, поскольку их легче понять. Прежде всего, итератор - это объект, у которого имеется метод .next(). Это не совсем верно, но достаточно близко. На самом деле, большая часть контекстов требует объект, который сгенерирует итератор, когда к нему применяется новая встроенная функция iter(). Для того, чтобы определенный пользователем класс (который имеет необходимый метод .next())возвращал итератор, нужно всего лишь обеспечить возврат self методом __iter__(). Примеры ниже пояснят сказанное. Метод .next() может вызвать исключение StopIteration, если итерация логически завершилась.

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

В некоторой степени генераторы похожи на замыкания (closure), о которых шла речь в предыдущих статьях о функциональном программировании. Подобно замыканию, генератор "помнит" состояние своих данных. Но с генератором можно достигнуть большего в том смысле, что он также"помнит" свою позицию в пределах структуры управления потоком данных (что в императивном программировании нечто большее, чем просто значения данных). Продолжения по-прежнему более общие конструкции, поскольку они позволяют произвольно перемещаться между кадрами стека, а не всегда возвращаться в контекст вызывающей функции (как делает генератор).

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

Случайное блуждание

С целью пояснения, позвольте мне поставить довольно простую задачу, которую можно решить различными способами: как новыми, так и старыми. Предположим, мы хотим получить поток случайных чисел меньших единицы, которые подчиняются обратному ограничению. А именно, мы хотим, чтобы каждое следующее число было, по крайней мере, на 0.4 больше или меньше предыдущего. Более того, сам поток не бесконечен, а заканчивается после случайного числа шагов. Например, мы прервем его, как только появится число меньшее 0.1. Описанные ограничения несколько схожи с теми, что можно найти в алгоритме"случайного блуждания", причем условие окончания напоминает"локальный минимум", но, определенно, эти требования мягче, чем при решении реальных задач.

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

# RandomWalk_List.py #
import random
def randomwalk_list():
    # инициализация потенциальных элементов
    last, rand = 1,random.random()
    # пустой список
    nums = []
    # условие прерывания
    while rand > 0.1:
        #принятие числа
        ifabs(last-rand) >= 0.4:
            last= rand
            #добавление последнего
            #элемента в nums
            nums.append(rand)
        else:
            #отображение отклонения
            print'*',
        #новый потенциальный элемент
        rand= random.random()
    # добавление последнего малого элемента
    nums.append(rand)
    return nums

Использовать эту функцию очень просто:

# Iterate over Random Walk List #
for num in randomwalk_list():
    print num,

Однако данный подход обладает ощутимыми ограничениями. Крайне маловероятно, что данный пример сгенерирует длинный список; но, сделав условие прерывания более жестким, мы могли бы создавать произвольно длинные потоки (их точный размер будет случайным, но порядок величин можно спрогнозировать). В определенный момент проблемы памяти и эффективности могут сделать этот подход неприемлемым и излишним. Именно эта проблема и вынудила добавить функции xrange() и xreadlines() в более ранние версии Python. Еще более существенно то, что многие потоки зависят от внешних событий, и все же они должны быть обработаны, когда каждый элемент доступен. Например, поток может слушать порт или ожидать ввода пользователя. В этих случаях создание полного списка из такого потока просто неприемлемо. Python 2.1 и более ранние версии предлагали еще один прием: можно было использовать"статическую" локальную переменную для запоминания информации о последнем вызове функции. Очевидно, глобальные переменные могли бы сделать тоже самое, но они порождают хорошо знакомые проблемы: засоряют глобальное пространство имен и допускают ошибки, вызванные нелокальностью. Возможно, это вас удивит - если вы не знакомы с этой хитростью - в Python нет "официального"объявления статической области. Однако, если именованные параметры имеют изменяемые значения по умолчанию, они могут быть долговременными хранилищами предыдущих вызовов. Списки, в частности, удобные изменяемые объекты, которые могут содержать даже множественные значения.

Используя "статический" подход мы можем написать следующую функцию:

# RandomWalk_Static.py #
import random
# инициализация "статических" переменных
def randomwalk_static(last=[1]):
    # инициализация возможного результата
    rand = random.random()
nbsp;   # условие прерывания
    if last[0] < 0.1:
        #признак конца потока
        returnNone
    # поиск приемлемого кандидата
    while abs(last[0]-rand) <0.4:
         #отображение отклонения
         print'*',
         #новый кандидат
         rand= random.random()
    # обновить"статическую" переменную
    last[0] = rand
    return rand

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

Автор: David Mertz, Ph.D., Autodidact, Gnosis Software,Inc.
Перевод: Intersoft Lab

    © 2003-2009 Copyright by A. Danilyuk