Опубликован: 22.12.2005 | Доступ: свободный | Студентов: 16502 / 504 | Оценка: 4.18 / 3.71 | Длительность: 16:16:00
ISBN: 978-5-9556-0109-0
Лекция 3:

Элементы функционального программирования

Простые генераторы

Разработчики языка не остановились на итераторах. Как оказалось, в интерпретаторе Python достаточно просто реализовать простые генераторы. Под этим термином фактически понимается специальный объект, вычисления в котором продолжаются до выработки очередного значения, а затем приостанавливаются до возникновения необходимости в выдаче следующего значения. Простой генератор формируется функцией-генератором, которая синтаксически похожа на обычную функцию, но использует специальный оператор yield для выдачи следующего значения. При вызове такая функция ничего не вычисляет, а создает объект с интерфейсом итератора для получения значений. Другими словами, если функция должна возвращать последовательность, из нее довольно просто сделать генератор, который будет функционально эквивалентной "ленивой" реализацией. Ленивыми называются вычисления, которые откладываются до самого последнего момента, когда получаемое в результате значение сразу используется в другом вычислении.

Для примера с последовательностью Фибоначчи можно построить такой вот генератор:

def Fib(N):
  a, b = 0, 1
  for i in xrange(N):
    yield a
    a, b = b, a + b

Использовать его не сложнее, чем любой другой итератор:

for i in Fib(100):
  print i,

Однако следует заметить, что программа в значительной степени упростилась.

Генераторное выражение

В Python 2.4 по аналогии со списковым включением появилось генераторное выражение. По синтаксису оно аналогично списковому, но вместо квадратных скобок используются круглые. Списковое включение порождает список, а, значит, можно ненароком занять очень много памяти. Генератор же, получающийся в результате применения генераторного выражения, списка не создает, он вычисляет каждое следующее значение строго по требованию (при вызове метода next() ).

В следующем примере можно прочесть из файла строки, в которых производятся некоторые замены:

for line in (l.replace("- ", " - ") for l in open("input.dat")):
  print line

Ничто не мешает использовать итераторы и для записи в файл:

open("output.dat", "w").writelines(
        l.replace("- ", " - ") for l in open("input.dat"))

Здесь для генераторного выражения не потребовалось дополнительных скобок, так как оно расположено внутри скобок вызова функции.

Карринг

Библиотека Xoltar toolkit (автор Bryn Keller) включает модуль functional, который позволяет упростить использование возможностей функционального программирования. Модуль functional применяет "чистый" Python. Библиотеку можно найти по адресу: http://sourceforge.net/projects/xoltar-toolkit.

При карринге (частичном применении) функции создается новая функция, задавая некоторые аргументы исходной. Следующий пример иллюстрирует частичное применение вычитания:

from functional import curry
def subtract(x, y):
    return x - y

print subtract(3, 2)
subtract_from_3 = curry(subtract, 3)
print subtract_from_3(2)
print curry(subtract, 3)(2)

Во всех трех случаях будет выведено 1. В следующем примере получается новая функция, подставляя второй аргумент. Вместо другого аргумента вставляется специальное значение Blank:

from functional import curry, Blank
def subtract(x, y):
    return x - y

print subtract(3, 2)
subtract_2 = curry(subtract, Blank, 2)
print subtract_2(3)
print curry(subtract, Blank, 2)(3)

Заключение

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

Следует отметить, что итераторы - это практичное продолжение функционального начала в языке Python. Итераторы по сути позволяют организовать так называемые ленивые вычисления (lazy computations), при которых значения вычисляются только когда они непосредственно требуются.

Ссылки по теме

Статья Д. Мертца http://www-106.ibm.com/developerworks/library/l-prog.html

Часто задаваемые вопросы в comp.lang.functional http://www.cs.nott.ac.uk/~gmh/faq.html

Андрей Егоров
Андрей Егоров

def bin(n):

"""Цифры двоичного представления натурального числа """

if n == 0:

   return []

n, d = divmod(n, 2)

return bin(n) + [d]

print bin(69)

Что значит здесь return[] ? Возвращает список? Непонятно какой список? Откуда он? 

 

 

Асмик Гаряка
Асмик Гаряка

Почему при вычислении рейтинга не учитывается уровень, как описано? Для всех курсов У=1, хотя для Специалист должно быть 2.

Аделина Федорова
Аделина Федорова
Россия, 155900