Файл: Учебное пособие С. К. Буйначев н. Ю. Боклаг.pdf

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 10.01.2024

Просмотров: 733

Скачиваний: 16

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

41
Функции, принимающие в качестве аргументов или возвраща- ющие другие функции в результате их выполнения, называютфунк- циями высшего порядка. В большинстве случаев таким образом стро- ится механизм обратных вызовов (callbacks), но встречаются и другие варианты. Например, алгоритм поиска может вызывать переданную ему функцию для каждого найденного объекта.
20.1. Функция аррlу()
Функция apply() применяет функцию, переданную в качестве первого аргумента, к параметрам, которые переданы вторым и треть- им аргументом. Эта функция в Python устарела, так как вызвать функцию можно с помощью обычного синтаксиса вызова функции.
Позиционные и именованные параметры можно передать с использо- ванием звездочек:
>>> lst = [1, 2, 3]
>>> dct= {'a' : 4, 'b' : 5}
>>> apply(max, lst)
3
>>> apply(dict, [], dct)
{'a': 4, 'b': 5}
20.2. Обработка последовательностей
Многие алгоритмы сводятся к обработке массивов данных и по- лучению новых массивов данных в результате. Среди встроенных функций Python есть несколько для работы с последовательностями.
Подпоследовательностьюв Python понимается любой тип дан- ных, который поддерживает интерфейс последовательности (это не- сколько специальных методов, реализующих операции над последо- вательностями, которые в данном курсе обсуждаться не будут).
Следует заметить, что тип, основной задачей которого является хранение, манипулирование и обеспечение доступа к самостоятель- ным данным, называетсяконтейнерным типомили простоконтейне- ром.Примеры контейнеров в Python – списки, словари.
20.2.1. Функции range() и xrange()
Функция range() уже упоминалась при рассмотрении цикла for.
Эта функция принимает от одного до трех аргументов. Если аргумент

42 всего один, то она генерирует список чисел от 0 (включительно) до заданного числа (исключительно). Если аргументов два, то список начинается с числа, указанного первым аргументом. Если аргументов три, то третий аргумент задает шаг.
>>> print range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print range(1, 10)
[1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> print range(1, 10, 3)
[1, 4, 7]
Функция xrange() – аналог range(), более предпочтительный для использования при последовательном доступе, например в цикле for или с итераторами. Она возвращает специальный xrange-объект, который ведет себя почти как список, порождаемый range(), но не хранит в памяти все выдаваемые элементы.
20.2.2. Функция map()
Для применения некоторой функции ко всем элементам после- довательности применяется функция map(f, *args). Первый параметр этой функции – функция, которая будет применяться ко всем элемен- там последовательности. Каждый следующий (n + 1)-й параметр должен быть последовательностью, так как каждый его элемент будет использован в качестве n-го параметра при вызове функции f().
В итоге получим список, составленный из результатов выполнения этой функции.
В следующем примере складываются значения из двух списков:
>>> l1 = [2, 7, 5, 3]
>>> l2 = [-2, 1, 0, 4]
>>> print map(lambda x,у: х+у, l1, l2)
[0, 8, 5, 7]
В этом примере применена безымянная функция для получения суммы двух операндов ко всем элементам l1 и l2. В случае, если одна из последовательностей короче другой, вместо соответствующего операнда будет использоватться None, что, конечно, собьет операцию


43 сложения. В зависимости от решаемой задачи можно либо видоизме- нить функцию, либо считать разные по длине последовательности ошибкой, которую нужно обрабатывать как отдельную ветвь алго- ритма.
Частный случай применения map() – использование None в ка- честве первого аргумента. В этом случае просто формируется список кортежей из элементов исходных последовательностей:
>>> l1 = [2, 7, 5, 3]
>>> l2 = [-2, 1, 0, 4]
>>> print map(None, l1, l2)
[(2, -2), (7, 1), (5, 0) , (3, 4)]
20.2.3. Функция filter()
Другой часто встречающейся операцией является фильтрование исходной последовательности в соответствии с некоторым предика- том (условием). Функция filter(f,seq) принимает два аргумента: функцию с условием и последовательность, из которой берутся зна- чения. В результирующую последовательность попадут только те значения из исходной, для которой f() возвратит истину. Если в каче- стве f задано значение None, результирующая последовательность будет состоять из тех значений исходной, которые имеют истинност- ное значение True. Например, в следующем фрагменте кода можно избавиться от символов, которые не являются буквами:
>>>filter(lambda x: x.isalpha(),'Hi,there! I am eating an apple.')
' Hitherelameatinganapple'
1   2   3   4   5

20.2.4. Списковые включения Для более естественной записи обработки списков в Python была внесена новинка – списковые включения. Фактически это специальный сокращенный синтаксис для вложенных циклов, for и условий if, внутри которых определенное выражение добавляется к списку, например: all_pairs = [] for i in range(5) : for j in range(5) : if i <= j: all_pairs.append((i, j))

44
Все это можно записать в виде спискового включения так: all_pairs = [(i, j) for i in range (5) for j in range (5) if i <= j]
Как легко заметить, списковые включения позволяют заменить map() и filter() на более удобные для прочтения конструкции.
В нижеприведенной таблице даны эквивалентные выражения в разных формах.
В форме функции
В форме спискового включе- ния filter(f, lst)
[x for x in 1st if f(x)] filter(None, lst)
[x for x in 1st if x] map(f, lst)
[f(x) for x in lst]
20.2.5. Функция sum()
Получить сумму элементов можно с помощью функции sum ():
>>> sum(range(10))
45
Эта функция работает только для числовых типов, она не может кон- катенировать строки. Для конкатенации списка строк следует исполь- зовать метод join().
>>>L=['Мама ','мыла ','раму.']
>>>join(L)
'Мама мыла раму.'
20.2.6. Функция reduce()
Для организации цепочечных вычислений (вычислений с накоп- лением результата) можно применять функцию reduce(), которая принимает три аргумента: функцию двух аргументов, последователь- ность и начальное значение. С помощью этой функции можно, в частности, реализовать функцию sum():

45 def sum(lst, start): return reduce(lambda x, y: x + y, lst, start)
В качестве передаваемого объекта может оказаться список, ко- торый позволит накапливать промежуточные результаты. Тем самым reduce() может использоваться для порождения последовательно- стей. lst = range(10) f = lambda x, y: (x[0] + y, x[1]+[x[0] + y]) print reduce(f, lst, (0, []))
В итоге получается:
(45, [0, 1, 3, 6, 10, 15, 21, 28, 36, 45])
20.2.7. Функция zip()
Функция zip() возвращает список кортежей, в котором 1-й кор- теж содержит i-e элементы аргументов-последовательностей. Длина результирующей последовательности равна длине самой короткой из последовательностей аргументов:
>>> print zip(range(5), "abcde")
[(0, 'а'), (1,'b'), (2, 'с'), (3, 'd'), (4, 'e')]
20.2.8. Итераторы
Применять для обработки данных явные последовательности не всегда эффективно, так как на хранение временных данных может тратиться много оперативной памяти. Более эффективным решением представляется использованиеитераторов – специальных объектов, обеспечивающих последовательный доступ к данным контейнера.
Если в выражении есть операции с итераторами вместо контейнеров, то промежуточные данные не будут требовать много места для хра- нения – они запрашиваются по мере необходимости для вычислений.
При обработке данных с использованием итераторов память будет требоваться только для исходных данных и результата, да и то необя- зательно вся сразу – ведь данные могут читаться и записываться в файл на диске.
Итераторы можно применять вместо последовательности в опе- раторе for. Более того, оператор for запрашивает у последовательно-


46 сти ее итератор. Объект файлового типа – тоже (построчный) итера- тор, что позволяет обрабатывать большие файлы, не считывая их це- ликом в память.
Использовать итератор можно и вручную. Любой объект, под- держивающий интерфейс итератора, имеет метод next(), который при каждом вызове выдает очередное значение итератора. Если больше значений нет, то возбуждается исключение StopIteration. Для полу- чения итератора по некоторому объекту необходимо прежде приме- нить к этому объекту функцию iter() (цикл for делает это автоматиче- ски).
В Python имеется модуль itertools, который содержит набор функций, комбинируя которые, можно составлять достаточно слож- ные схемы обработки данных с помощью итераторов. Далее рассмат- риваются некоторые функции этого модуля.
20.2.9. Функция iter()
Функция iter() имеет два варианта использования. В первом она принимает всего один аргумент, который должен «уметь» предостав- лять свой итератор. Во втором один из аргументов – функция без ар- гументов, другой – стоповое значение. Итератор вызывает указанную функцию до тех пор, пока та не возвратит стоповое значение. Второй вариант встречается много реже первого и обычно внутри метода класса, так как сложно порождать значения «на пустом месте»: it1 = iter([1, 2, 3, 4, 5]) def forit(mystate=[]): if len(mystate)<3: mystate.append(" ") return " " it2 = iter(forit,None) print[x for x in it1] print [x for x in it2]
Если функция не возвращает значения явно, то она возвращает
None, что и использовано в примере выше.
20.2.10. Функция enumerate()
Функция enumerate() создает итератор, нумерующий элементы другого итератора. Результирующий итератор выдает кортежи, в ко-

47 торых первый элемент – номер (начиная с нуля), а второй – элемент исходной последовательности:
>>> print [x for x in enumerate("abcd")]
[(0, 'а'), (1, 'b'), (2, 'с'), (3, 'd')]
20.2.11. Функция sorted()
Функция sorted(), появившаяся в версии Python 2.4, позволяет создавать итератор, выполняющий сортировку:
>>> sorted('avdsdf)
['a' , 'd' , 'd' , 'f, 's' , 'v']
20.2.12. Модуль itertools
Функция itertools.chain() позволяет сделать итератор, состоя- щий из нескольких соединенных последовательно итераторов. Итера- торы задаются в виде отдельных аргументов: from itertools import chain it1 = iter([1,2,3]) it2 = iter([8,9,0]) for i in chain(it1, it2): print i, # даст 123890
Функция itertools.repeat() строит итератор, повторяющий неко- торый объект заданное количество раз:
>>>for i in itertools.repeat(1,4): print i,
1111
Бесконечный итератор itertools.count() используется так: for i in itertools.count(1): print i, if i > 100: break
Можно бесконечно повторять и некоторую последовательность
(или значения другого итератора) с помощью функции itertools.cycle ():


48 tango = [1, 2, 3] for i in itertools.cycle(tango): print i,
Аналогами map() и filter() в модуле itertools являются iter- tools.imap() и itertools.ifilter(). Отличие itertools.imap() от map() за- ключается в том, что вместо значения от преждевременно завершив- шихся итераторов объект None не подставляется:
>>>for i in map(lambda х,у:(х,у),[1,2],[1,2,3]): print i,
(1,1) (2,2) (None,3)
>>>from itertools import imap
>>>for i in imap(lambda х,y:(x,y),[1,2],[1,2,3]): print i,
(1, 1) (2, 2)
Здесь следует заметить, что обычная функция mар() нормально воспринимает итераторы в любом сочетании с итерабельными (под- дающимися итерациям) объектами:
>>>for i in map(lambda x, y: (x,y) , iter([1,2]),[1,2,3]): print i,
(1, 1) (2, 2) (None, 3)
Функция itertools.starmap() подобна itertools.imap(), но имеет всего два аргумента. Второй аргумент – последовательность корте- жей, каждый кортеж которой задает набор параметров для функции
(первого аргумента):
>>> from itertools import starmap
>>> for i in starmap(lambda x, y: str(x) +y, [(1,'a'),(2,'b')]): print i, la 2b
Функция ifilter() работает как filter(). Кроме того, в модуле iter- tools есть функция ifilterfalse(), которая добавляет отрицание к значе- нию функции:
>>>for i in ifilterfalse(lambda x: x>0,[1,-2,3,-3]): print i,
-2 -3

49
Некоторую новизну вносит другой вид фильтра iter- tools.takewhile() и его «отрицательный» аналог itertools.dropwhile().
Следующий пример поясняет их принцип действия: for i in takewhile(lambda x: x > 0, [1, -2, 3, -3]): print i, print for i in dropwhile(lambda x: x >0,[1,-2,3,-3]): print i,
Обобщенная природа функций Python и полиморфизм, не завя- занный целиком на наследовании, – вот свойства языка Python, поз- воляющие иметь большую гибкость в комбинации процедурного и объектно-ориентированного подходов.
21. МАТРИЧНЫЕ ВЫЧИСЛЕНИЯ
Здесь приводится обзор других пакетов для научных вычис- лений.
Numeric Python –это несколько модулей для вычислений с многомерными массивами, необходимых для многих численных приложений. Модуль Numeric вносит в Python возможности таких пакетов и систем, как MatLab, Octave(аналог MatLab), APL, J, S+,
IDL. Стоит заметить, что некоторые синтаксические возможности Py- thon, связанные с использованием срезов, были специально разрабо- таны для Numeric.
Numeric Python имеет средства для:
● матричных вычислений LinearAlgebra;
● быстрого преобразования Фурье FFT;
● работы с недостающими экспериментальными данными MA;
● статистического моделирования RNG;
● эмуляции базовых функций программы MatLab.
21.1. Модуль Numeric
Модуль Numeric определяет полноценный тип-массив и содер- жит большое число функций для операций с массивами.Массивэто набор однородных элементов, доступных по индексам. Массивы мо- дуля Numeric могут быть многомерными, то есть иметь более одной
размерности.