[МУЗЫКА] [МУЗЫКА] Итак,
приступим к практическому изучению функционального программирования.
Некоторые функции для работы с последовательностями вы уже знаете.
Давайте я их просто напишу.
Это функция sum, которая умеет суммировать с любой iterable, который ему передается.
Это функции max и min для поиска максимума
и минимума в последовательности, а также функция map,
которая умеет применять функцию к каждому элементу iterable.
Мы обычно использовали это для чтения последовательности чисел.
В принципе, можно применять и свои какие-то функции или другие функции,
не только преобразования.
А также это sorted — функция,
которая возвращает отсортированную последовательность.
Главное, что мы уже немножко попробовали
использовать лямбда-функции, передавая их в качестве параметра k,
чтобы отсортировать по какому-то хитрому параметру, производному от наших данных.
И map.
Вот они пять функций, пять элементов функционального
программирования для обработки последовательности, которые мы уже знаем.
Кроме этого, существует еще масса функций.
Мы, конечно же, посмотрим не все, но некоторые наиболее часто употребляемые,
если так можно сказать вообще о функциональном программировании,
что что-то в нем употребляется часто.
Эти пять, конечно, очень важны и пригодятся в любом случае.
Итак, некоторые новые функции.
Есть функция filter, записывается как filter.
У нас всплывают подсказки, в каком порядке нужно писать параметры.
Здесь была подсказка function_or_None, то есть функция или ничего.
Что такое фильтр?
Фильтр позволяет отфильтровать элементы последовательности.
Например, что мы можем сделать?
Мы можем решить с помощью фильтра такую задачу.
Считать последовательность чисел и напечатать,
например, только положительные числа.
Что мы для этого сделаем?
Пока что будем писать не совсем в функциональном стиле,
то есть сохраним в переменную, потом переделаем программу.
Для начинающих такой подход очень хороший.
Список делать необязательно, достаточно iterable,
поэтому слово list мы писать не будем здесь.
Итак, вот мы считали наши данные и теперь
к этой последовательности применим фильтр — функцию,
которая возвращает истину только для положительных чисел.
Мы хотим сделать это в виде лямбда-функции,
потому что она очень простая.
(lambda x : x > 0).
Она вернет значение «истина», когда x > 0, и «ложь» в противном случае.
В качестве второго параметра фильтра передаем
последовательность, которую нужно обработать.
Она вернет тоже последовательность,
давайте мы ее напечатаем с помощью звездочки.
Проверим, как это все у нас работает.
Итак, вот у нас некоторое количество положительных чисел, отрицательное, 0,
еще 0 и еще что-нибудь.
Запускаем, и действительно остаются только положительные числа.
Теперь немножко о том, как писать совсем в функциональном стиле.
В функциональном программировании стараются использовать исключительно
неизменяемые объекты и вообще-то часто не используют переменные совсем.
То есть вот эта переменная numbers нам, в принципе, не нужна,
мы можем чтение вставить прямо вот здесь.
У нас получится такая одна строка, всего одна строка для решения этой задачи.
Это здорово, но когда задачи будут сложнее, строка будет разрастаться,
и у вас какая-то далеко выезжающая за пределы экрана получится одна длинная
колбаса символов, в которой ничего невозможно понять.
В функциональном программировании с непривычки и так ничего нельзя понять,
но давайте попытаемся навести хоть какой-то порядок.
В прошлом занятии мы в словаре наводили порядок
и здесь попробуем по аналогии поступить.
В чем идея?
Каждый параметр будет на новой строке.
Если параметров в функции несколько,
то они будут с тем же отступом написаны.
Если это бо́льшие вложения, то с бо́льшим отступом.
Среда нам сделала почти красиво.
Давайте мы попробуем сделать это совсем хорошо.
Здесь, смотрите, я не доделал: вот, вот, вот.
Мне кажется, что так более понятно, как я сейчас сделал.
Итак, теперь у нас строк стало девять вместо одной,
но хоть какое-то понимание того, что происходит, появилось.
У нас отступами обозначаются
фактически новые вложенные функции.
Читать это нужно с более вложенных к менее вложенным.
Если вдруг вам на работе, например, в проекте попадется любитель
функционального программирования, даже если вы сами не пишете в таком стиле,
то хотя бы понять, что он написал, было бы очень полезно.
Как это читать?
Начинаем с наиболее вложенного.
Вот оно, map.
Что мы здесь можем увидеть?
В принципе, достаточно понятно.
Мы делаем список чисел.
Затем берем следующий по вложенности уровень — filter.
Мы знаем, что такое filter.
Вот у нас первый параметр — это функция, когда у нас все хорошо.
И вот второй параметр — список чисел, мы уже знаем,
то есть мы отфильтровали положительные числа.
Переходя к самому внешнему уровню, мы понимаем,
что там у нас находится print — печать, то есть мы печатаем результат фильтрации.
Вот так вот мы прочитали функциональную программу, не то чтобы даже снизу вверх,
а с наиболее вложенного к наименее вложенному.
Такой порядок чтения.
Продолжим изучение условно полезных функций.
Еще одна функция это enumerate — занумеровать.
Давайте я на очень простом примере покажу,
а потом мы еще вернемся к ней, она нам пригодится.
Для чего она нужна?
Она нужна для нумерации элементов последовательности.
Единственный параметр, который она принимает, это сама последовательность.
И необязательный параметр — с какого числа начинать нумеровать.
Итак, давайте какие-нибудь буквы там напишем,
просто чтобы у нас они явно отличались от чисел.
Кстати, зачем я делаю список?
Мы же можем передать любой iterable, например строку.
Не забываем ставить звездочку в print, чтобы у нас печаталось содержимое именно.
И вот, что мы получаем.
Мы получаем кортежи, вначале стоит номер,
нумерация с 0, а затем стоит очередной элемент,
взятый из того, что мы передали в качестве параметра.
Таким образом, мы можем что-то занумеровать, и иногда это бывает полезно.
Еще две полезные функции — это any и all.
Что такое any и all?
Any возвращает истину, если хотя бы один элемент из iterable, который
должен состоять из bool, из логических значений, истинный, хотя бы один.
Давайте я, опять же, на очень простом примере покажу.
Пусть у нас три элемента: True, False, True.
Хотя бы один из них равен true, то есть мы ожидаем получить true.
All — это значит, все элементы истинны.
Но у нас не все, мы получаем false.
В таком виде, конечно, это не применяется.
Когда это применяется чаще всего?
Допустим, вы хотите узнать, все ли числа вашей последовательности положительны.
Что для этого нужно сделать?
Нужно написать такую конструкцию.
Давайте, я попробую писать с нуля в функциональном стиле, хотя, опять же,
вам, как начинающим, не рекомендую так делать.
Итак, мы хотим понять все ли элементы последовательности положительны.
Для этого мы применим к нашей входной последовательности функцию,
лямбда-функцию, которая возвращает истину, если число положительное.
Мы такую уже писали.
Это первый параметр нашего map.
Второй параметр — это чтение списка чисел, еще один map вложенный.
[ЗВУК] Кажется,
что мы закончили написание наши программы,
осталось поставить только звездочку, она должна возвращать «истину»,
если все введенные числа положительные, и «ложь» в противном случае.
Давайте посмотрим.
[ЗВУК] Звездочка не нужна,
потому что мы возвращаем bool, это я уже по привычке к iterable.
Итак, в случае, когда все числа положительные, мы получили 1, 2, 3.
Когда у нас хоть одно число отрицательное, мы получаем False.
Как вы видите, писать в функциональном стиле
привычно слева направо достаточно сложно.
Почему?
Потому что нам приходится все время думать,
а что же мы сделаем дальше, и поэтому разумно писать, начиная с конца.
Мы сейчас на примере более сложной задачи посмотрим, как программу,
написанную не в чисто функциональном стиле, эффективно переделать так,
что это будет выглядеть так, что никто ничего не поймет.
[МУЗЫКА]
[МУЗЫКА]