← Часть 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))
Подведем итоги
Анонимные функции не могут в полной мере заменить обычные: синтаксис допускает использование всего одного выражения. Однако лямбда-выражения способны обрабатывать неограниченное количество аргументов, могут содержать любые условия и операторы сравнения, и их можно упаковать в список или словарь. В тех случаях, когда функция используется однократно, в особенности для фильтрации данных, лямбда-выражения очень удобны.
В следующей статье будем изучать рекурсивные функции.
***
Содержание самоучителя
Особенности, сферы применения, установка, онлайн IDE
Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
Типы данных: преобразование и базовые операции
Методы работы со строками
Методы работы со списками и списковыми включениями
Методы работы со словарями и генераторами словарей
Методы работы с кортежами
Методы работы со множествами
Особенности цикла for
Условный цикл while
Функции с позиционными и именованными аргументами
Анонимные функции
Больше полезных материалов вы найдете на нашем телеграм-канале «Библиотека питониста» Интересно, перейти к каналу