Почему полезны лямбды Python? [закрыто]


929

Я пытаюсь выяснить Python лямбды. Является ли лямбда одним из тех «интересных» языковых предметов, которые в реальной жизни следует забыть?

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

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


261
+1 Хороший вопрос - плохие предположения (неясность лямбды) =) Постарайтесь не осуждать приемы программирования. Оцените их и добавьте в свой интеллектуальный инструментарий. Если они вам не нравятся, не используйте их и будьте готовы обсуждать их логически, не становясь религиозными.
Кьевели

41
Правила Haskell! Лямбда-функции дают вам силу выразительности и абстракции.
Джонатан Барберо

11
@JAL Не говоря уже о LISP ...
ApproachingDarknessFish

8
@ApproachingDarknessFish "Ах, это скобка твоего отца. Более цивилизованное оружие из более цивилизованного возраста." - Оби Лисп Кеноби
Поля

Ответы:


1009

Вы говорите о лямбда-функциях ? подобно

lambda x: x**2 + 2*x - 5

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

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

устанавливает mult3на [3, 6, 9]те элементы исходного списка, которые кратны 3. Это короче (и, можно утверждать, яснее), чем

def filterfunc(x):
    return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

Конечно, в этом конкретном случае вы можете сделать то же самое, что и понимание списка:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(или даже как range(3,10,3)), но есть много других, более сложных случаев использования, когда вы не можете использовать понимание списка, и лямбда-функция может быть кратчайшим способом записать что-либо.

  • Возврат функции из другой функции

    >>> def transform(n):
    ...     return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    Это часто используется для создания оболочек функций, таких как декораторы Python.

  • Объединение элементов итерируемой последовательности с reduce()

    >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • Сортировка по альтернативному ключу

    >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

Я использую лямбда-функции на регулярной основе. Мне потребовалось некоторое время, чтобы привыкнуть к ним, но в конце концов я понял, что они очень ценная часть языка.


26
Люблю примеры, очень легко понять. Но для уменьшения. Если я должен реализовать эту функцию. Я бы сделал','.join(str(x) for x in [1,2,3,4,5,6,7,8,9])
etlds

3
Кстати, если вы запускаете это на Python3, вам нужно вызвать список результатов фильтрации, чтобы увидеть фактические значения, а также вам нужно импортировать сокращение из functools
Джерард

Уверены ли мы в определении «функционального программирования» выше? Это немного смутило меня.
stdout

3
Я думаю, что ключевым моментом является то, что lambdaфункции могут быть анонимными (как они есть во всех ваших примерах). Если вы назначаете lambdaфункцию чему-либо, то вы делаете это неправильно и должны использовать defвместо этого
Chris_Rands

1
@zgulser Это не определение, это просто утверждение о том, что функциональное программирование позволяет вам делать.
Дэвид Z

377

lambdaэто просто модный способ сказать function. Кроме его имени, в этом нет ничего темного, пугающего или загадочного. Когда вы читаете следующую строку, заменить lambdaна functionв своем уме:

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

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

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

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


36
Это отличное описание для тех, кто не имеет опыта программирования (например, точные науки), что делает его значение lambda очень простым для понимания. Спасибо!
Габриэль

10
Рэймонд Хеттингер пожаловался на имя в одном из своих выступлений и сказал, что можно было бы избежать путаницы, назвав его «make function» вместо «lambda». :-)
ankush981

10
заменить lambdaна functionв своем уме и добавить returnпозапрошлый выражение
Ciprian Tomoiagă

4
@AaronMcMillin Попробуй type(lambda x: 3). lambdaвыражения и defоператоры генерируют functionобъекты; это только синтаксис lambdaвыражения, который ограничивает экземпляры, которые оно может производить.
Чепнер

6
@AaronMcMillin Вы упускаете мою точку зрения. То, что вы не можете определить каждую функцию с помощью lambdaвыражения, не означает, что результат lambdaвыражения не является функцией.
chepner

107

Двухстрочная сводка:

  1. Закрытие : очень полезно. Изучи их, используй их, люби их.
  2. lambdaКлючевое слово Python : не нужно, иногда полезно. Если вы обнаружите, что делаете с ним что-то сложное, уберите это и определите реальную функцию.

72

Лямбда является частью очень важного механизма абстракции, который имеет дело с функциями более высокого порядка. Чтобы правильно понять его ценность, посмотрите высококачественные уроки Абельсона и Суссмана и прочитайте книгу SICP.

Это актуальные проблемы современного программного обеспечения, которые становятся все более популярными.


1
Лямбда-выражения становятся популярными и в других языках (например, C #). Они никуда не денутся. Чтение замыканий было бы полезным упражнением для понимания лямбд. Замыкания делают возможной большую магию кодирования в таких средах, как jQuery.
Дэн Эспарза

3
Не путайте lambdaс и первоклассные функции. Python имеет чрезвычайно ограниченную lambdaформулировку, но полностью первоклассные функции. Единственное отличие, которое он имеет, заключается в том, что вы должны называть функции, которые хотите передать.
Гарет Латти

59

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

for value in ["one","two","three"]:
    b = tk.Button(label=value, command=lambda arg=value: my_callback(arg))
    b.pack()

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

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


1
Именно поэтому я посмотрел, что такое лямбда, но почему это работает, для меня это выглядит точно так же, как простой вызов функции ( stackoverflow.com/questions/3704568/… ). Может быть, уже поздно, это работает, но почему это работает?
Rqomey

5
@Rqomey: разница в том, что в этом примере valueопределяется в цикле; в другом примере параметр всегда имел только одно значение. Когда вы добавляете что-то подобное arg=value, вы присоединяете текущее значение к обратному вызову. Без этого вы привязываете ссылку на переменную в обратном вызове. Ссылка всегда будет содержать окончательное значение переменной, поскольку обратный вызов происходит через некоторое время после завершения цикла.
Брайан Оукли

1
Я только что заработал вчера, я, честно говоря, не могу поверить, насколько это полезно ... Я могу создать меню из одного цикла for и файла csv для конфигурации. Действительно полезные вещи.
Rqomey

1
Обратите внимание на наличие functools.partial()чего позволяет делать это с меньшими затратами (и без lambda).
Гарет Латти

2
partial(my_callback, value)vs lambda arg=value: my_callback(arg)- у лямбды гораздо больше беспорядка (назначение arg, а затем использование), и менее ясно, каково намерение (вы могли бы делать что-то немного другое в лямбде). Импорт на самом деле не является проблемой (у вас все равно есть куча, и это один раз на файл). Код лучше оценивать по тому, насколько хорошо он читается, и partial()его гораздо легче читать, чем лямбду.
Гарет Латти

58

Я сомневаюсь, что лямбда уйдет. Посмотрите пост Гвидо о том, что он, наконец, отказался от попыток удалить его. Также см. Схему конфликта .

Вы можете проверить этот пост, чтобы узнать больше о сделке, стоящей за функциональными возможностями Python: http://python-history.blogspot.com/2009/04/origins-of-pythons-functional-features.html

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

Мои собственные два цента: Редко стоит лямбда, насколько ясность идет. Как правило, есть более четкое решение, которое не включает лямбду.


2
Обратите внимание, что уменьшение все еще импортируется в Python 3.0. Если Вы ДЕЙСТВИТЕЛЬНО хотите этого, Вы все еще можете это иметь.
Павел Полевич,

Я думаю, что попытка Гвидо была больше о синтаксисе. Этот человек также считает, что: cackhanded.com/blog/post/2008/01/24/...
leewz

38

В Python lambdaэто просто способ определения встроенных функций,

a = lambda x: x + 1
print a(1)

а также..

def a(x): return x + 1
print a(1)

.. точный же.

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

>>> a = lambda x: x + 1
>>> type(a)
<type 'function'>

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

Для совершенно случайного примера из статьи "Лямбда Python сломана!" :

Чтобы увидеть, как ломается лямбда, попробуйте сгенерировать список функций fs=[f0,...,f9]где fi(n)=i+n. Первая попытка:

>>> fs = [(lambda n: i + n) for i in range(10)]
>>> fs[3](4)
13

Я бы сказал, что даже если бы это сработало, это ужасно и «не пифонично», такую ​​же функциональность можно написать бесчисленным множеством других способов, например:

>>> n = 4
>>> [i + n for i in range(10)]
[4, 5, 6, 7, 8, 9, 10, 11, 12, 13]

Да, это не то же самое, но я никогда не видел причину, по которой требуется генерация группы лямбда-функций в списке. Это может иметь смысл в других языках, но Python - это не Haskell (или Lisp, или ...)

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

>>> fs = [(lambda n,i=i: i + n) for i in range(10)]
>>> fs[3](4)
7

Редактировать:

Есть несколько случаев, когда лямбда полезна, например, она часто удобна при подключении сигналов в приложениях PyQt, например:

w = PyQt4.QtGui.QLineEdit()
w.textChanged.connect(lambda event: dothing())

Просто выполнение w.textChanged.connect(dothing)вызовет dothingметод с дополнительным eventаргументом и вызовет ошибку. Использование лямбды означает, что мы можем аккуратно отбросить аргумент без необходимости определения функции обтекания.


2
ваш аргумент "лямбда не работает" не работает, потому что правила области видимости переменных python работают именно так, точка. Вы будете укушены таким же образом, если вы создали замыкание внутри цикла for.
Антти Хаапала

1
Лямбда - это просто способ python предоставить пользователю «анонимную» функцию, как и во многих других языках (например, javascript).
Стефан Грюнвальд,

1
Лямбда и функции a, которые вы определили, не совсем одинаковы. :) Они различаются по __name__полю по крайней мере ...
nperson325681

1
Это работает больше, чем просто встроенная функция.
кт

Ваш аргумент о «может иметь смысл на другом языке» странный. Либо есть внутренние качества лямбд, либо их нет.
Титу

31

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

Как правила множественного числа Mozilla :

plural_rules = [
    lambda n: 'all',
    lambda n: 'singular' if n == 1 else 'plural',
    lambda n: 'singular' if 0 <= n <= 1 else 'plural',
    ...
]
# Call plural rule #1 with argument 4 to find out which sentence form to use.
plural_rule[1](4) # returns 'plural'

Если бы вам нужно было определить функцию для всех, вы бы сошли с ума до конца.
Кроме того, было бы плохо с именами функций, такими как plural_rule_1, plural_rule_2и т. Д. И вам это понадобится, eval()когда вы зависите от идентификатора переменной функции.


1
Это похоже на краткие встречи, которые у меня были до сих пор в F # с сопоставлением с образцом и опциями. У вас есть больше информации о том, как использовать этот синтаксис?
Кен

26

Практически все, что вы можете сделать с lambda вами, может быть лучше с именованными функциями или выражениями списка и генератора.

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


3
«По большей части вы должны просто один из тех, в основном в любой ситуации» Период. Ввод лямбды в интерпретаторе даже не очень полезен.
S.Lott

11
@Javier Я согласен с вами, если вы говорите о «лямбда-концепции»; однако, если мы говорим о «лямбде» ключевого слова python, то: 1) именованные функции быстрее и могут делать больше (операторы + выражения) почти везде, где бы вы ни использовали лямбда-выражения (карта + фильтр), вы можете просто генерировать выражения или составлять списки которые являются более производительными и краткими. Я не говорю, что функции первого класса не крутые, просто то, что ключевое слово «лямбда» в python не так хорошо, как использование именованной функции, вот и все.
Аарон Маэнпаа

3
Лямбда была мне незаменима для использования с функциями, которые принимают аргументы обратного вызова, такие как key = аргумент для sort () и sorted ()
Рик Коупленд

19
@ Рик: Я не сомневаюсь в этом, но реальность такова, что когда вы видите «лямбду» и думаете «zohmygod lambda» и начинаете писать код схемы на python, вы будете разочарованы ограничениями лямбда-выражения python. С другой стороны, если вы начнете думать про себя: «Будет ли работать понимание списка? Нет. Будет ли то, что мне нужно, быть названной функцией? Нет. Хорошо, хорошо: sorted (xs, key = lambda x: x.name, x.height) ", вы, вероятно, в конечном итоге будете использовать лямбду нужное количество раз.
Аарон Маэнпаа

4
+1: я не могу подчеркнуть, что достаточно, когда кто-то использует лямбду, он использует безымянную функцию. И имена имеют ценную интеллектуальную добавленную стоимость.
Стефан Роллан

19

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


8
Они очень полезны при разработке GUI с использованием Python. Часто виджетам нужна ссылка на функцию. Если вам нужен виджет для вызова функции и передачи аргументов, лямбда - очень удобный способ сделать это.
Брайан Оукли

1
В чем преимущество передачи нескольких аргументов в функцию? func_name (a, b): возвращать a + b вместо использования лямбды
dter

2
это не нужно, но помогает писать более короткий код и во многих случаях более читабельно, особенно. в многословных языках, таких как Java или C ++
phuclv

17

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

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


3
Это можно сделать без лямбд. Это просто большая проблема.
Брайан

17

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

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

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

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

Увидеть разницу?

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

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

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

[]: «Дайте мне список»

х ** 2: «используя эту функцию новорожденного»

для х в: «в каждый элемент в»

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

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

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

(я) одна функция

(ii) повторяемый

И дает вам список, где каждый элемент - это функция, примененная к каждому элементу итерируемого.

Итак, используя карту мы получили бы:

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

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


13

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

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

log_timestamp(datetime.datetime.now() - datetime.timedelta(minutes = 30))

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

log_timestamp(lambda : datetime.datetime.now() - datetime.timedelta(minutes = 30))

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

Конечно, есть альтернативные способы сделать это (например, с помощью operatorмодуля), но я надеюсь, что я передал эту мысль.

Обновление : вот немного более конкретный пример из реального мира.

Обновление 2 : я думаю, что это пример того, что называется гром .


11

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

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

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

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

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

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

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

  • Существует неявный возврат, то есть они кажутся «должны» быть функциями.

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

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


1
"... в Python функции являются замыканиями". Это не совсем верно, насколько я понимаю. Замыкания - это функции, но функции не всегда замыкания. Функция-> лямбда х, у: х + у. Закрытие-> лямбда x: лямбда y: x + y
0atman

6
«потому что лямбда-исчисление не является полным по Тьюрингу», это неверно, нетипизированное лямбда-исчисление является полным по Тьюрингу, поэтому оно так важно. Вы можете получить рекурсию, используя Y-комбинатор,Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
Антти Хаапала

Кроме того, если кто-то отправляется в Википедию, чтобы прочитать о полноте Тьюринга, он говорит: «Классическим примером является лямбда-исчисление».
Антти Хаапала

серьезно - не завершено по Тьюрингу - этот ответ требует серьезного редактирования или отвода.
Тони Саффолк 66

@ MarcinŁoś проголосовал за, потому что он придерживается KISS. Для сравнения, книга K & R упоминает, что, хотя использование присваивания как части или более крупного выражения более компактно, оно часто менее читабельно. Тенденция использования шаблонов функционального программирования - банально и клише. Достаточно указать, как их можно использовать, но чрезмерно усердно утверждать, что они имеют первостепенное значение для становления компетентным разработчиком; полностью субъективно. Этот аргумент аналогичен разработчикам на C ++, которые утверждают, что языки без классов являются примитивными, неполноценными и неадекватными. «Тьюринг-полнота», аргументы педантичны.
typedeaf

11

Лямбды на самом деле являются очень мощными конструкциями, основанными на идеях функционального программирования, и это то, что никоим образом не будет легко пересмотрено, переопределено или удалено в ближайшем будущем 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):
    #Your code to execute on the event trigger

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

def main():
    # define widgets and other imp stuff
    x, y = None, None
    widget.bind("<Button-1>", lambda event: do-something-cool(x, y))

def do-something-cool(event, x, y):
    x = event.x
    y = event.y
    #Do other cool stuff

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

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


Спасибо. Я не совсем понял ваш последний пример. Почему x и y определены в обоих mainи do_something_cool? Что происходит xи yв функции? Переданные значения кажутся немедленно перезаписанными? Как функция узнает о event? Не могли бы вы добавить несколько комментариев / объяснений? Спасибо
Санджай Манохар

@SanjayManohar Я передаю xи в yкачестве аргументов do-something-coolи их значения устанавливаются в функции, чтобы проиллюстрировать, как вы можете использовать лямбда-выражения для передачи аргументов, где ни один не ожидается. widget.bindФункция ожидает eventпараметр , который идентифицирует событие GUI на этом конкретный виджете. Я рекомендую прочитать модель программирования Tkinter для большей ясности.
varagrawal

хм, думаю, я понимаю модель Tkinter. Но до сих пор не совсем понимаю - ты проходишь, а x,yпотом делаешь x=event.x. Разве это не перезаписывает значение, которое вы передали? А как функция узнает, что eventесть? Я не вижу, где вы передаете это функции. Или это метод? Также разрешены ли знаки минус в имени функции?
Санджай Манохар

@SanjayManohar приятель, вы должны прочитать о Tkinter и Python. Tkinter передает объект события функции как действие по умолчанию. Что касается того x, y, что это только пример для иллюстративных целей. Я пытаюсь показать силу лямбд, а не Ткинтера. :)
varagrawal

1
Хорошо, теперь я понимаю, что вы намеревались - вы хотите, чтобы функция получила event? в таком случае, не должна ли ваша лямбда читать lambda event: do_something_cool(event,x,y)?
Санджай Манохар

8

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

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


7

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

Вы просто должны думать немного по-другому. Я уверен, что скоро вам это понравится. Но будьте осторожны, если вы имеете дело только с питоном. Поскольку лямбда не является настоящим закрытием, она как-то «сломана»: лямбда-питоны сломана


Лямбда Питона не сломана. Есть два способа обращаться с местными жителями в лямбдах. Оба имеют свои преимущества и недостатки. Я думаю, что подход, принятый Python (и C #), вероятно, противоречит интуиции тех, кто более привык к чисто функциональным языкам, поскольку с чисто функциональным языком я не думаю, что такой подход имеет смысл.
Брайан

Это действительно нелогично. Я не программист на Python, но в Squeak Smalltalk это то же самое, и я регулярно сталкиваюсь с этим. Так что даже я бы посчитал это «сломанным» :)
Норберт Хартл

Нет, это не имеет ничего общего с контринтуитивностью. Просто лексическая область имен переменных - это область функции; цикл не вводит лексическую область видимости. Функции также работают в Javascript. Если вам нужна область видимости для var, вы всегда можете сделать это (лямбда-скопедвар: лямбда-х: скопедвар + х) ()
Антти Хаапала

6

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

Обратите внимание, что это не осуждение чего-либо. У каждого свой набор вещей, которые нелегко придут.

Является ли лямбда одним из тех «интересных» языковых предметов, которые в реальной жизни следует забыть?

Нет.

Я уверен, что есть некоторые крайние случаи, когда это могло бы быть необходимо, но учитывая неясность этого,

Это не неизвестно. Последние 2 команды, над которыми я работал, все использовали эту функцию все время.

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

Я не видел серьезных предложений переопределить его в Python, кроме исправления семантики замыкания несколько лет назад.

и уменьшенная ясность кодирования - этого следует избегать?

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

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

Лямбда это как переполнение буфера? Ух ты. Я не могу представить, как вы используете лямбду, если думаете, что это «кошмар обслуживания».


5
-1 за то, что заставил меня (и других) прочитать весь вопрос снова. Обратите внимание, что другие смогли ответить, не делая этого.
Павел Полевич,

6

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

def a_func()
  ...
  if some_conditon:
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)
  else
     ...
     call_some_big_func(arg1, arg2, arg3, arg4...)

Я заменяю это на временную лямбду

def a_func()
  ...
  call_big_f = lambda args_that_change: call_some_big_func(arg1, arg2, arg3, args_that_change)
  if some_conditon:
     ...
     call_big_f(argX)
  else
     ...
     call_big_f(argY)

5

Сегодня я начал читать книгу Дэвида Мерца «Обработка текста в Python». В то время как у него есть довольно лаконичное описание лямбды, примеры в первой главе в сочетании с объяснением в Приложении А заставили их спрыгнуть со страницы (наконец) для меня, и внезапно я понял их ценность. Это не значит, что его объяснение сработает для вас, и я все еще на стадии открытия, поэтому я не буду пытаться добавить к этим ответам, кроме следующего: я новичок в Python, я новичок в ООП. Лямбды были борьбой за меня. Теперь, когда я прочитал Mertz, я думаю, что получил их, и считаю их очень полезными, так как я думаю, что они позволяют более чистый подход к программированию.

Он воспроизводит Дзен Питона, одна строка которого Проста лучше, чем сложна. Как не-ООП программист, читающий код с лямбдами (и до прошлой недели в списках), я подумал: это просто? , Сегодня я наконец понял, что на самом деле эти функции делают код намного более читабельным и понятным, чем альтернатива, которая неизменно представляет собой своего рода цикл. Я также понял, что, как и финансовые отчеты, Python не предназначен для начинающего пользователя, скорее он предназначен для пользователя, который хочет получить образование. Я не могу поверить, насколько силен этот язык. Когда до меня дошло (наконец-то) цель и значение лямбд, я хотел разорвать около 30 программ и начать заново вводить лямбды, где это уместно.


5

Полезным примером использования лямбд является улучшение читаемости длинных списков . В этом примере loop_dicкоротко для ясности, но представьте, loop_dicчто оно очень длинное. Если бы вы просто использовали простое значение, которое включает iвместо лямбда-версии этого значения, вы бы получили NameError.

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> loop_dic = lambda i: {"name": i["name"] + " Wallace" }
>>> new_lis = [loop_dic(i) for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

Вместо

>>> lis = [{"name": "Peter"}, {"name": "Josef"}]

>>> new_lis = [{"name": i["name"] + " Wallace"} for i in lis]

>>> new_lis
[{'name': 'Peter Wallace'}, {'name': 'Josef Wallace'}]

5

Я могу привести пример, когда мне действительно нужна серьезная лямбда. Я делаю графическую программу, где использую правой кнопкой мыши файл и назначаю ему один из трех вариантов. Оказывается, что в Tkinter (программе интерфейса GUI, в которой я пишу это), когда кто-то нажимает кнопку, он не может быть назначен команде, которая принимает аргументы. Поэтому, если я выбрал один из вариантов и хотел, чтобы результатом моего выбора было:

print 'hi there'

Тогда ничего страшного. Но что, если мне нужен мой выбор, чтобы иметь конкретную деталь? Например, если я выбираю вариант A, он вызывает функцию, которая принимает некоторый аргумент, зависящий от выбора A, B или C, TKinter не может это поддерживать. Ламда была единственной возможностью обойти это на самом деле ...


2
Ну, по-видимому, вы могли бы сделать, def foo...а затем передать fooвместо lambda. Это просто больше кода, и вы должны придумать имя.
Джон Кумбс

4

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

Вот примеры:

реализовать шаблон нулевого объекта:

{
    DATA_PACKET: self.handle_data_packets
    NET_PACKET: self.handle_hardware_packets
}.get(packet_type, lambda x : None)(payload)

для привязки параметров:

скажем, у меня есть следующий API

def dump_hex(file, var)
    # some code
    pass

class X(object):
    #...
    def packet_received(data):
        # some kind of preprocessing
        self.callback(data)
    #...

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

dump_file = file('hex_dump.txt','w')
X.callback = lambda (x): dump_hex(dump_file, x)
...
dump_file.close()

4

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

Например:

import imported.module

def func():
    return lambda: imported.module.method("foo", "bar")

в отличие от:

import imported.module

def func():
    def cb():
        return imported.module.method("foo", "bar")
    return cb

4

Я новичок в Python, поэтому, чтобы получить четкое представление о лямбде, я сравнил его с циклом for; с точки зрения эффективности. Вот код (Python 2.7) -

import time
start = time.time() # Measure the time taken for execution

def first():
    squares = map(lambda x: x**2, range(10))
    # ^ Lambda
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0 seconds

def second():
    lst = []
    for i in range(10):
        lst.append(i**2)
    # ^ a 'for' loop
    end = time.time()
    elapsed = end - start
    print elapsed + ' seconds'
    return elapsed # gives 0.0019998550415 seconds.

print abs(second() - first()) # Gives 0.0019998550415 seconds!(duh)

6
Возможно, вас заинтересует timeitмодуль, который обычно дает более точные результаты, чем вычитание time.time()значений.
Кевин

2
Хм, а вам не нужно перезапускать таймер при запуске first () и second ()?
qneill

2

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.