Share This
Связаться со мной
Крути в низ
Categories
//Анонимная функция (lambda-функция) в Python

Анонимная функция (lambda-функция) в Python

Изучаем особенности лямбда-функций в Python: разбираемся, когда стоит использовать анонимные функции вместо обычных, и в каких случаях lambda-выражения лучше заменить списковыми включениями. В конце статьи – 10 практических заданий с решениями.

anonimnaja funkcija lambda funkcija v python 88b361c - Анонимная функция (lambda-функция) в Python

← Часть 11 Функции с позиционными и именованными аргументами

Происхождение названия

Лямбда-функции часто называют анонимными потому, что такую функцию можно определить с помощью оператора lambda, не давая ей название. Происхождение термина «лямбда» связано с формальной системой λ-исчисления.

Назначение и особенности анонимных функций в Python

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

         def discr(b, a, c):     return b ** 2 - 4 * a * c      

А так – анонимная:

         lambda b, a, c: b ** 2 - 4 * a * c     

2. Анонимные функции используются однократно, в том участке кода, где были определены. Если функцию нужно вызывать многократно, следует написать обычную функцию def. Чаще всего анонимные функции используют совместно со встроенными функциями map(), filter(), sorted(), min(), max() и т. п. Особенно удобно применять лямбда-функции для сортировки:

         mydict = {'слива':5, 'папайя':6, 'лук':56, 'маракуйя':78, 'ежевика':45}  print('До сортировки: ', mydict) sorted_mydict = dict(sorted(mydict.items(), key=lambda item: len(item[0]))) print('После сортировки: ', sorted_mydict)      

Вывод:

         До сортировки:  {'слива': 5, 'папайя': 6, 'лук': 56, 'маракуйя': 78, 'ежевика': 45} После сортировки:  {'лук': 56, 'слива': 5, 'папайя': 6, 'ежевика': 45, 'маракуйя': 78}      

3. Присваивание лямбда-функциям имен не приводит к ошибке, но считается плохой практикой в соответствии с рекомендациями PEP8, поскольку противоречит самой концепции анонимности: такие функции используются однократно, и поэтому имена им не нужны:

         #Можно, но не нужно max_num = lambda a, b : a if a > b else b  #Правильно def max_num(a, b):     return a if a > b else b       

4. Анонимные функции вызываются сразу после определения. Здесь лямбда-функция выполняет сортировку списка словарей по возрастанию цены:

         fruit = [     {'название':'виноград',      'цена': 230,      'количество': 412     },     {'название':'манго',      'цена': 350,      'количество': 21     },     {'название':'бананы',      'цена': 70,      'количество': 234     },     {'название':'яблоки',      'цена': 66,      'количество': 213     },     ] print(sorted(fruit, key=lambda item: item['цена']))      

Вывод:

         [{'название': 'яблоки', 'цена': 66, 'количество': 213}, {'название': 'бананы', 'цена': 70, 'количество': 234}, {'название': 'виноград', 'цена': 230, 'количество': 412}, {'название': 'манго', 'цена': 350, 'количество': 21}]     

5. Анонимные функции могут принимать неограниченное количество аргументов, но не могут содержать более одного выражения. Если в определении лямбда-функции записать два и более выражений, интерпретатор вернет ошибку:

         lambda a : a + 10, a - 5     

Сообщение об ошибке:

         NameError: name 'a' is not defined     

6. Лямбда-функции можно включать в тело обычных функций. Эта функция будет удваивать все получаемые значения:

         def my_function(n):   return lambda a : a * n double = my_function(2) print(double(15))  # Вывод: 30     

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

         st = 'яжертыуиопшщасдфгчйклзхцвбнм' vowels = 'аиеёоуыэюя' result = list(map(lambda x: 'гласная' if x in vowels else 'согласная', st)) print(result)      

Вывод:

         ['гласная', 'согласная', 'гласная', 'согласная', 'согласная', 'гласная', 'гласная', 'гласная', 'гласная', 'согласная', 'согласная', 'согласная', 'гласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная', 'согласная']     

А в этом примере анонимная функция выбирает из исходного списка четные числа, превосходящие 6:

         numbers = [7, 8, 6, 9, 4, -6, 2, 0, -3, -12, -5, -2, 12, 77, 32] print(list(filter(lambda x: x > 6 and x % 2 == 0, numbers)))      

8. Анонимные функции являются замыканиями – им доступны внешние переменные. В этом примере внутренняя лямбда-функция принимает список и возвращает минимальный или максимальный элемент в зависимости от соответствующего параметра внешней функции:

         def get_min_or_max(value='max'):     return eval(f'lambda x: {value}(x)')   lst = [3, 5, -22, -15, 100, 7, 8, 9, 12, 98]   max_func = get_min_or_max() min_func = get_min_or_max('min') print(max_func(lst)) print(min_func(lst))      

Вывод:

         100 -22      

9. В отличие от обычных функций, анонимные не могут содержать return, pass, assert и raise.

10. Подобно обычным функциям, лямбда-выражения поддерживают различные типы аргументов:

  • позиционные;
  • именованные;
  • смешанные (позиционные + именованные);
  • *args;
  • **kwargs.

11. Лямбда-функции для проведения последовательных операций можно хранить в списках:

         ops = [(lambda x, y: x + y), (lambda x, y: x - y),        (lambda x, y: x * y), (lambda x, y: x / y)]  x, y = int(input()), int(input()) for i in range(len(ops)):     print(ops[i](x, y))  # Пример вывода для x = 12, y = 15: 27 -3 180 0.8     

А также в словарях:

         ops = {'neg': lambda x: abs(x), 'pos': lambda x: x / 2, 'zero': lambda x: x + 5} lst = list(map(int, input().split())) for i in lst:     if i < 0:         print(ops['neg'](i))     elif i > 0:         print(ops['pos'](i))     else:         print(ops['zero'](i))  # Пример вывода для 4 -5 0 6 -3: 2.0 5 5 3.0 3      

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

         my_list = [3, 5, 6, 7, 2, 8, 9, 10] cubes = map(lambda x: pow(x, 3), my_list) # или x ** 3 print(list(cubes))      

Однако тот же результат можно получить проще:

         print([i ** 3 for i in my_list])        

Вывод:

         [27, 125, 216, 343, 8, 512, 729, 1000]     

А здесь лямбда-функция используется для выбора четных чисел из списка:

         my_list = [4, 2, 3, 5, 16, 12, 2, 8, 9, 10] print(list(filter(lambda x: x % 2 == 0, my_list)))      

Вывод:

         [4, 2, 16, 12, 2, 8, 10]     

Точно такой же результат даст простое списковое включение:

         print([i for i in my_list if i % 2 == 0])     

Очень часто лямбда-функции используются совместно с filter():

         lst = ['ролл', 'яблоко', 'книга', 'шар', 'ноутбук']  print(list(filter(lambda x: len(x) > 4, lst)) ) print(list(filter(lambda x: 'р' in x, lst)))      

В этом случае списковые включения также выглядят проще:

         print([i for i in lst if len(i) > 4]) print([i for i in lst if 'р' in i])      

Вывод:

         ['яблоко', 'книга', 'ноутбук'] ['ролл', 'шар']      

Практика

Задание 1

Напишите программу, которая получает от пользователя список, состоящий из целых чисел, и находит произведение его элементов. Решите задачу тремя способами:

  • с помощью reduce и лямбда-функции;
  • с math.prod();
  • с использованием пользовательской функции.

Пример ввода:

         3 5 6 7 8 2 4 3 4     

Вывод:

         483840     

Решение 1:

         from functools import reduce  lst = list(map(int, input().split())) print(reduce(lambda x, y: x * y, lst))      

Решение 2:

         import math lst = list(map(int, input().split())) print(math.prod(lst))      

Решение 3:

         def prod(lst):     prod = 1     for i in lst:         prod *= i     return prod  lst = list(map(int, input().split())) print(prod(lst))      

Задание 2

Напишите программу для сортировки значений словаря в алфавитном порядке.

Словарь:

         unsorted_dict = {'фрукт': 'яблоко', 'цвет': 'антрацит', 'артикул': 'в5678',                  'модель': 'бабочка', 'наименование': 'книга', 'жанр': 'триллер'}      

Ожидаемый результат:

         {'цвет': 'антрацит', 'модель': 'бабочка', 'артикул': 'в5678', 'наименование': 'книга', 'жанр': 'триллер', 'фрукт': 'яблоко'}     

Решение:

         unsorted_dict = {'фрукт': 'яблоко', 'цвет': 'антрацит', 'артикул': 'в5678',                  'модель': 'бабочка', 'наименование': 'книга', 'жанр': 'триллер'} print(dict(sorted(unsorted_dict.items(), key=lambda item: item[1])))      

Примечание: некоторые задачи, связанные с сортировкой словаря, можно также решать с помощью zip():

         print(dict(sorted(zip(unsorted_dict.values(), unsorted_dict.keys()))))     

Задание 3

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

Пример ввода:

         физалис груша слива арбуз банан апельсин яблоко папайя     

Вывод:

         арбуз банан груша слива     

Решение 1:

         my_lst = input().split() print(*sorted(list(filter(lambda x: len(x) == 5, my_lst))))      

Решение 2:

         my_lst = input().split() print(*sorted([i for i in my_lst if len(i) == 5]))      

Задание 4

Напишите программу, которая:

  • определяет текущую дату с помощью datetime.datetime.now();
  • извлекает информацию о дне, месяце и годе с помощью анонимных функций;
  • выводит день, месяц и год на экран.

Пример вывода:

         день: 13 месяц: 1 год: 2023      

Решение:

         import datetime now = datetime.datetime.now() date = [['день', lambda x: x.day], ['месяц', lambda x: x.month], ['год', lambda x: x.year]] for i in date:     print(f'{i[0]}: {i[1](now)}')      

Примечание: без лямбда-функций задачу можно решить так:

         import datetime now = str(datetime.datetime.now()) date = now.split()[0].split('-') print(f'день: {date[2]}'       f'nмесяц: {date[1]}'       f'nгод:  {date[0]}'       )      

Задание 5

Напишите программу, которая получает целое число n и выводит n первых элементов последовательности Фибоначчи.

Пример ввода:

         12     

Вывод:

         0 1 1 2 3 5 8 13 21 34 55 89     

Решение:

         from functools import reduce   fibonacci = lambda n: reduce(lambda x, n: x + [x[-1] + x[-2]], range(n - 2), [0, 1]) n = int(input()) print(*fibonacci(n))      

Задание 6

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

Пример ввода:

         3 6 7 8 9 2 1 0 12 45 7 9 0 12 15 5 6 11 43      

Вывод:

         Пересечение: 7 9 0 12 6     

Решение:

         lst1 = list(map(int, input().split())) lst2 = list(map(int, input().split()))  intersection = list(filter(lambda x: x in lst1, lst2))  print('Пересечение:', *intersection)      

Задание 7

Напишите программу, которая сортирует полученную от пользователя строку с числами следующим образом:

  • отрицательные числа идут после положительных;
  • и положительные, и отрицательные числа упорядочены по возрастанию.

Пример ввода:

         -6 -1 3 -5 -15 4 1 9 8 6 -3 -4 12 -10 7     

Вывод:

         1 3 4 6 7 8 9 12 -15 -10 -6 -5 -4 -3 -1     

Решение:

         lst = list(map(int, input().split())) print(*sorted(lst, key = lambda i: 0 if i == 0 else -1 / i))      

Задание 8

Напишите программу, которая получает от пользователя две строки с числами, и выводит третью строку с поэлементными суммами чисел из первой и второй строк.

Пример ввода:

         7 2 3 -5 6 7 0 1 12 45 9 33 32 87 12 -2 4 7 1 3 9 2 4 2      

Вывод:

         39 89 15 -7 10 14 1 4 21 47 13 35     

Решение:

         lst1 = list(map(int, input().split())) lst2 = list(map(int, input().split()))  print(*list(map(lambda x, y: x + y, lst1, lst2)))      

Примечание: другой способ решения задачи – с использованием zip():

         for i, j in zip(lst1, lst2):     print(i + j, end=' ')      

Задание 9

Напишите программу, которая получает 1) строку с набором слов; 2) одно слово, не входящее в предыдущую строку, и находит все анаграммы слова в строке.

Пример ввода:

         каприз клоун колба колун крона уклон колыбель карта кулон      

Вывод:

         клоун колун уклон     

Решение:

         lst = input().split() word = input() print(*list(filter(lambda x: (set(word) == set(x)), lst)))      

Задание 10

Напишите программу для проверки надежности пароля. Надежный пароль должен содержать не менее 9 символов; кроме того, в пароле должна быть хотя бы одна:

  • буква в верхнем регистре;
  • буква в нижнем регистре;
  • цифра;
  • и хотя бы один символа из набора !@#$%^&*()-+.

Пример ввода 1:

         Введите пароль для проверки:  password      

Вывод:

         В пароле должна быть хотя бы одна буква в верхнем регистре  В пароле должна быть хотя бы одна цифра  Пароль должен содержать один из спецсимволов !@#$%^&*()-+  Пароль должен содержать не менее 9 символов      

Пример ввода 2:

         Введите пароль для проверки:  Mur#zilka98     

Вывод:

         Надежный пароль     

Решение:

         def check_password(passw):     res_dict = [     lambda passw: any(x.isupper() for x in passw) or 'nВ пароле должна быть хотя бы одна буква в верхнем регистре',     lambda passw: any(x.islower() for x in passw) or 'nВ пароле должна быть хотя бы одна буква в нижнем регистре ',     lambda passw: any(x.isdigit() for x in passw) or 'nВ пароле должна быть хотя бы одна цифра',     lambda passw: any(x in '!@#$%^&*()-+' for x in passw) or 'nПароль должен содержать один из спецсимволов !@#$%^&*()-+',     lambda passw: len(passw) >= 9 or 'nПароль должен содержать не менее 9 символов']     result = [x for x in [i(passw) for i in res_dict] if x != True]     if not result:         result.append('Надежный пароль')     return result     st = input('Введите пароль для проверки: ') print(*check_password(st))     

Подведем итоги

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

В следующей статье будем изучать рекурсивные функции.

***

Содержание самоучителя

  1. Особенности, сферы применения, установка, онлайн IDE
  2. Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
  3. Типы данных: преобразование и базовые операции
  4. Методы работы со строками
  5. Методы работы со списками и списковыми включениями
  6. Методы работы со словарями и генераторами словарей
  7. Методы работы с кортежами
  8. Методы работы со множествами
  9. Особенности цикла for
  10. Условный цикл while
  11. Функции с позиционными и именованными аргументами
  12. Анонимные функции

Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу

  • 0 views
  • 0 Comment

Leave a Reply

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Этот сайт использует Akismet для борьбы со спамом. Узнайте, как обрабатываются ваши данные комментариев.

Связаться со мной
Close