9

Каковы преимущества использования лямбд? [закрыто]

10

Проблема: Я пытаюсь разобраться с лямбда-функциями в Python. Является ли lambda одной из тех "интересных" особенностей языка, которые в реальной жизни стоит забыть?

Я уверен, что существуют некоторые пограничные случаи, когда они могут понадобиться, но учитывая их неопределённость и возможность изменения в будущих версиях (это моё предположение, основанное на различных их определениях), а также ухудшение читаемости кода — стоит ли их избегать?

Это напоминает мне о переполнении буфера в C, когда указатель ссылается на верхнюю переменную и перезаписывает значения других полей. Это выглядит как некая техническая демонстрация, но является кошмаром для поддержки кода.

5 ответ(ов)

4

lambda — это просто модное слово для обозначения функции. За его названием не скрывается ничего запутанного, пугающего или загадочного. Когда вы читаете следующую строку, замените lambda на функцию в своем уме:

>>> f = lambda x: x + 1
>>> f(3)
4

Это просто определяет функцию от x. В некоторых других языках, таких как R, это выражается более явно:

> f = function(x) { x + 1 }
> f(3)
4

Видите? Это одна из самых естественных вещей в программировании.

0

В целом, всё, что можно сделать с помощью lambda, можно сделать лучше с использованием именованных функций или выражений списков и генераторов.

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

0

Лямбда-функция — это небюрократичный способ создания функции.

Например, представим, что у вас есть основная функция, и вам нужно возвести в квадрат значения. Давайте посмотрим, как это можно сделать традиционным способом и с помощью лямбда-функции:

Традиционный способ:

def main():
    ...
    y = square(some_number)
    ...
    return something

def square(x):
    return x**2

Лямбда-способ:

def main():
    ...
    square = lambda x: x**2
    y = square(some_number)
    return something

Видите разницу?

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

>>> a = [1, 2, 3, 4]
>>> [x**2 for x in a]
[1, 4, 9, 16]

Давайте разберем, что означает каждый элемент синтаксиса:

  • [] : "Дайте мне список"
  • x**2 : "используя эту вновь созданную функцию"
  • for x in a : "для каждого элемента в a"

Удобно, да? Создавать функции таким образом. Давайте перепишем это с использованием лямбды:

>>> square = lambda x: x**2
>>> [square(s) for s in a]
[1, 4, 9, 16]

Теперь давайте используем map, который делает то же самое, но более универсально. map принимает два аргумента:

  1. одна функция
  2. перебираемый объект (итератор)

И возвращает список, где каждый элемент — это результат применения функции к каждому элементу перебираемого объекта.

Таким образом, с использованием map мы можем сделать следующее:

>>> a = [1, 2, 3, 4]
>>> squared_list = list(map(lambda x: x**2, a))

Если вы овладеете лямбдами и map, вы получите большую силу для манипуляции данными и сможете делать это лаконично. Лямбда-функции не являются ни запутанными, ни ухудшают читаемость кода. Не путайте что-то сложное с чем-то новым. Как только вы начнете их использовать, вы поймете, что это очень прозрачно.

0

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

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

В целом, это сводится к нескольким пунктам:

  • Проще читать код, который явно написан с использованием значимых имен. Анонимные замыкания по определению не могут иметь значимого имени, так как у них нет имени. Эта краткость, почему-то, также "заражает" параметры лямбды, поэтому мы часто видим примеры вроде lambda x: x + 1.
  • Проще повторно использовать именованные замыкания, так как к ним можно обращаться по имени более одного раза, когда есть имя, на которое можно сослаться.
  • Проще отлаживать код, благодаря использованию именованных замыканий вместо лямбд, так как имя появляется в трассировках и вокруг ошибки.

Этого уже достаточно, чтобы собрать их и преобразовать в именованные замыкания. Однако я имею два других аргумента против анонимных замыканий.

Первый аргумент заключается в том, что они являются еще одним бесполезным ключевым словом, засоряющим язык.

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

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

Я стараюсь писать Python без лямбд и удалять их при первом же упоминании. Я считаю, что Python был бы немного лучшим языком без лямбд, но это всего лишь мое мнение.

0

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

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

squared = map(lambda x: x*x, [1, 2, 3, 4, 5])

Эта строка кода возвращает список квадратов чисел из исходного списка. Конечно, можно сделать это и так:

def square(x):
    return x*x

squared = map(square, [1, 2, 3, 4, 5])

Очевидно, что первый вариант короче, и это особенно актуально, если вы собираетесь использовать функцию map (или любую аналогичную функцию, принимающую функцию в качестве параметра) лишь в одном месте. Это также делает код более интуитивным и элегантным.

Кроме того, как упомянул @David Zaslavsky в своем ответе, списковые выражения не всегда являются единственным вариантом, особенно если вам нужно извлечь значения из сложной математической функции.

С практической точки зрения, одним из самых больших преимуществ лямбда-функций для меня в последнее время стало использование в GUI и событийно-ориентированном программировании. Если взглянуть на колбек-функции в Tkinter, они получают в качестве аргументов только событие, которое их вызвало. Например:

def define_bindings(widget):
    widget.bind("<Button-1>", do_something_cool)

def do_something_cool(event):
    # Ваш код для выполнения при срабатывании события

А что, если вам нужно передать какие-то аргументы? Например, простую задачу — передать 2 аргумента для хранения координат клика мышью. Вы легко можете сделать это так:

def main():
    # опишите виджеты и другие важные вещи
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do_something_cool(event, x, y))

def do_something_cool(event, x, y):
    x = event.x
    y = event.y
    # Выполните другие полезные действия

Можно возразить, что это можно сделать, используя глобальные переменные, но не хотите ли вы волноваться о управлении памятью и утечками, особенно если глобальная переменная будет использоваться только в одном конкретном месте? Это было бы просто плохим стилем программирования.

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

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь