В основном я использую лямбда-функции, но иногда использую вложенные функции, которые, кажется, обеспечивают такое же поведение.
Вот несколько тривиальных примеров, когда они функционально делают то же самое, если они были обнаружены в другой функции:
Лямбда-функция
>>> a = lambda x : 1 + x
>>> a(5)
6
Вложенная функция
>>> def b(x): return 1 + x
>>> b(5)
6
Есть ли преимущества в использовании одного перед другим? (Производительность? Читаемость? Ограничения? Последовательность? И т. Д.)
Это вообще имеет значение? Если этого не происходит, это нарушает принцип Питона:
Должен быть один - и желательно только один - очевидный способ сделать это .
lambda
, но я не согласен с тем, что это «очень редко», обычно для ключевых функцийsorted
иitertools.groupby
т. Д., Напримерsorted(['a1', 'b0'], key= lambda x: int(x[1]))
На практике у меня есть два отличия:
Первый касается того, что они делают и что возвращают:
def - это ключевое слово, которое ничего не возвращает и создает «имя» в локальном пространстве имен.
лямбда - это ключевое слово, которое возвращает объект функции и не создает «имя» в локальном пространстве имен.
Следовательно, если вам нужно вызвать функцию, которая принимает объект функции, единственный способ сделать это в одной строке кода Python - использовать лямбда. У def нет эквивалента.
В некоторых фреймворках это действительно довольно часто; например, я часто использую Twisted , поэтому делаю что-то вроде
довольно распространен и более краток с лямбдами.
Второе отличие заключается в том, что разрешено делать фактической функции.
Например,
работает как положено, а
это SyntaxError.
Конечно, есть обходные пути - заменить
print
наsys.stdout.write
илиimport
на__import__
. Но обычно в этом случае лучше использовать функцию.источник
В этом интервью Гвидо ван Россум говорит, что ему жаль, что он не пустил лямбду в Python:
ИМХО, ямбды иногда могут быть удобными, но обычно они удобны за счет удобочитаемости. Вы можете сказать мне, что это делает:
Я написал это, и мне потребовалась минута, чтобы понять это. Это из Project Euler - не скажу, какая проблема, потому что ненавижу спойлеры, но она выполняется за 0,124 секунды :)
источник
lambda
3.0 был близок, и что Гвидо не боролся за его сохранение.Для n = 1000 вот некоторое время для вызова функции по сравнению с лямбдой:
источник
Производительность:
Создание функции с
lambda
это немного быстрее , чем создавать егоdef
. Разница связана сdef
созданием записи имени в таблице locals. Полученная функция имеет такую же скорость выполнения.Читаемость:
Лямбда-функции несколько менее читабельны для большинства пользователей Python, но в некоторых случаях они гораздо более краткие. Рассмотрите возможность перехода от нефункциональной рутины к функциональной:
Как видите,
lambda
версия короче и «проще» в том смысле, что вам нужно только добавитьlambda v:
к исходной нефункциональной версии, чтобы преобразовать ее в функциональную. Это также намного более лаконично. Но помните, что многие пользователи Python будут сбиты с толку лямбда-синтаксисом, поэтому то, что вы потеряете в длине и реальной сложности, может быть получено обратно в замешательстве от других программистов.Ограничения:
lambda
функции можно использовать только один раз, если они не присвоены имени переменной.lambda
функции, присвоенные именам переменных, не имеют преимущества передdef
функциями.lambda
функции могут быть трудными или невозможными для маринования.def
Имена функций должны быть тщательно выбраны, чтобы они были достаточно информативными и уникальными или, по крайней мере, иначе не использовались в области действия.Последовательность:
Python в основном избегает соглашений о функциональном программировании в пользу процедурной и более простой объектной семантики.
lambda
Оператор находится в прямом противоречии с этим уклоном. Более того, как альтернатива уже распространенномуdef
,lambda
функция добавляет разнообразия в ваш синтаксис. Некоторые сочтут это менее последовательным.Ранее существовавшие функции:
Как отмечали другие, многие варианты использования
lambda
в полевых условиях могут быть заменены членами того жеoperator
или других модулей. Например:Использование уже существующей функции во многих случаях может сделать код более читабельным.
Принцип Питона: «Должен быть один - а желательно только один - очевидный способ сделать это»
Это похоже на доктрину единственного источника истины . К сожалению, принцип «единственно очевидный способ сделать это» всегда был для Python скорее задумчивым стремлением, чем истинным руководящим принципом. Рассмотрим очень мощное понимание массивов в Python. Они функционально эквивалентно
map
иfilter
функций:lambda
иdef
такие же.Это вопрос мнения, но я бы сказал, что все на языке Python, предназначенное для общего использования, что, очевидно, ничего не ломает, является достаточно «питоническим».
источник
У использования лямбда-выражений перед обычной функцией есть одно преимущество: они создаются в выражении.
Есть несколько недостатков:
'<lambda>'
)Они также являются объектами одного типа. По этим причинам я обычно предпочитаю создавать функции с
def
ключевым словом, а не с лямбдами.Первый момент - это объекты одного типа
Лямбда приводит к тому же типу объекта, что и обычная функция.
Поскольку лямбды - это функции, они являются объектами первого класса.
И лямбды, и функции:
Но в лямбдах по умолчанию отсутствуют некоторые вещи, которые функции получают через полный синтаксис определения функции.
Ламба -
__name__
это'<lambda>'
В конце концов, лямбды - это анонимные функции, поэтому они не знают своего имени.
Таким образом, лямбды нельзя искать программно в их пространстве имен.
Это ограничивает некоторые вещи. Например,
foo
можно найти сериализованный код, ноl
нельзя:Мы можем искать
foo
просто - потому что он знает свое собственное имя:У лямбда-выражений нет аннотаций и нет строки документации
В основном лямбды не документированы. Давайте перепишем,
foo
чтобы лучше документировать:Теперь у foo есть документация:
Принимая во внимание, что у нас нет такого же механизма для передачи той же информации лямбдам:
Но мы можем их взломать:
Но, вероятно, есть какая-то ошибка, которая портит вывод справки.
Лямбды могут возвращать только выражение
Лямбды не могут возвращать сложные инструкции, только выражения.
По общему признанию, выражения могут быть довольно сложными, и если вы очень постараетесь, вы, вероятно, сможете добиться того же с помощью лямбда, но дополнительная сложность больше мешает написанию четкого кода.
Мы используем Python для ясности и удобства обслуживания. Чрезмерное использование лямбд может сработать.
Только вверх для лямбды: может быть создано в одном выражении
Это единственно возможный потенциал роста. Поскольку вы можете создать лямбду с выражением, вы можете создать его внутри вызова функции.
Создание функции внутри вызова функции позволяет избежать (недорогого) поиска имени по сравнению с поиском в другом месте.
Однако, поскольку Python строго оценивается, это не дает никакого другого увеличения производительности, кроме отказа от поиска имени.
Для очень простого выражения я мог бы выбрать лямбду.
Я также предпочитаю использовать лямбды при работе с интерактивным Python, чтобы избежать нескольких строк, когда можно использовать одну. Я использую следующий формат кода, когда хочу передать аргумент конструктору при вызове
timeit.repeat
:И сейчас:
Я считаю, что небольшая разница во времени, указанная выше, может быть связана с поиском имени в
return_nullary_function
- обратите внимание, что это очень незначительно.Вывод
Лямбда-выражения хороши для неформальных ситуаций, когда вы хотите свести к минимуму строки кода в пользу выделения особой точки.
Лямбды плохи для более формальных ситуаций, когда вам нужна ясность для редакторов кода, которые придут позже, особенно в тех случаях, когда они нетривиальны.
Мы знаем, что должны давать нашим объектам хорошие имена. Как мы можем это сделать, если у объекта нет имени?
По всем этим причинам я обычно предпочитаю создавать функции с помощью,
def
а не сlambda
.источник
Я согласен с советом nosklo: если вам нужно дать функции имя, используйте
def
. Я резервируюlambda
функции для случаев, когда я просто передаю короткий фрагмент кода другой функции, например:источник
Соглашаясь с другими ответами, иногда это более читабельно. Вот пример, который
lambda
мне пригодится, в случае использования, с которым я постоянно сталкиваюсь с N-мернымdefaultdict
.Вот пример:
Я считаю это более читаемым, чем создание
def
второго измерения. Это еще более важно для более высоких измерений.источник
from functools import partial; defaultdict(partial(defaultdict, list))
. Назначьте партиал имени, если вы хотите использовать его более одного раза. Но если вы продолжаете встречать эту конструкцию, это означает, что вы не СУХИЙ. Разложите его на служебную библиотеку. Вы можете использовать эту конструкцию для создания произвольного n-мерного defaultdict с помощью других функций (или цикла или рекурсии).Основное использование лямбда всегда было для простых функций обратного вызова, а также для сопоставления, уменьшения и фильтрации, которые требуют функции в качестве аргумента. Со списком понимание становится нормой, а добавленное разрешено, если, как в:
Трудно представить себе реальный случай использования лямбда в повседневной жизни. В результате, я бы сказал, избегайте лямбда и создавайте вложенные функции.
источник
Важным ограничением лямбда-выражений является то, что они не могут содержать ничего, кроме выражения. Для лямбда-выражения практически невозможно произвести что-либо, кроме тривиальных побочных эффектов, поскольку оно не может иметь такого богатого тела, как
def
функция 'ed.При этом Lua повлиял на мой стиль программирования в сторону широкого использования анонимных функций, и я засорял ими свой код. Вдобавок ко всему, я склонен думать о map / reduce как о абстрактных операторах способами, которые я не рассматриваю в понимании списков или генераторах, почти как если бы я явно откладывал решение о реализации, используя эти операторы.
Редактировать: это довольно старый вопрос, и мое мнение по этому поводу несколько изменилось.
Во-первых, я категорически против присвоения
lambda
выражения переменной; поскольку у python есть специальный синтаксис только для этого (подсказкаdef
). В дополнение к этому, многие варианты использования лямбда, даже если они не получают имени, имеют предопределенные (и более эффективные) реализации. Например, рассматриваемый пример можно сократить до просто(1).__add__
, без необходимости заключать его в символыlambda
илиdef
. Многие другие распространенные применения могут быть удовлетворены некоторой комбинацией модулейoperator
,itertools
иfunctools
.источник
(1).__add__
- прямой вызов dunder-методов почти никогда не должен происходить. Тысячаlambda
с за каждый прямой вызов.(1).__add__
несколько необычны, но я бы даже близко не подошел к «следует». без сомнения, я считаю, что первое гораздо более читабельноlambda x: 1 + x
. Если бы у нас было что-то более похожее на нотацию срезов haskells,(1+)
это было бы здорово, но мы должны обойтись тем, что семантически является именно этой вещью, именем метода dunder.Рассмотрим простой пример,
источник
Если вы просто собираетесь присвоить лямбду переменной в локальной области видимости, вы также можете использовать def, потому что она более читабельна и может быть легко расширена в будущем:
или
источник
from operator import pow;map(pow, someList)
и(a**b for a,b in someList)
даже более читабельны.Я нашел одно использование лямбда-выражений ... в отладочных сообщениях.
Поскольку лямбды могут быть вычислены лениво, у вас может быть такой код:
вместо возможно дорогих:
который обрабатывает строку формата, даже если вызов отладки не производит вывод из-за текущего уровня ведения журнала.
Конечно, чтобы он работал, как описано, используемый модуль регистрации должен поддерживать лямбда-выражения как «ленивые параметры» (как это делает мой модуль регистрации).
Та же идея может быть применена к любому другому случаю ленивой оценки для создания ценности контента по запросу.
Например, этот пользовательский тернарный оператор:
вместо того:
с лямбда-выражениями будет оцениваться только выражение, выбранное условием, без лямбда-выражений будут оцениваться оба.
Конечно, вы можете просто использовать функции вместо лямбда-выражений, но для коротких выражений лямбда-выражения (c) более компактны.
источник
logging
уже имеет ленивое форматирование:log.debug("this is my message: %r", some_data)
будет форматироваться только тогда, когда / если сообщение запрошено.some_data
может быть дорогостоящее выражение или вызов функции / метода.Я согласен с носкло. Кстати, даже при однократном использовании функции выброса в большинстве случаев вы просто хотите использовать что-то из модуля оператора.
Например:
У вас есть функция с этой сигнатурой: myFunction (данные, функция обратного вызова).
Вы хотите передать функцию, которая добавляет 2 элемента.
Использование лямбда:
Питонический путь:
Или, конечно, это простой пример, но есть много вещей, которые предоставляет операторный модуль, включая установщики / получатели элементов для list и dict. Очень круто.
источник
Основное отличие состоит в том, что вы не можете использовать
def
встроенные функции, что, на мой взгляд, является наиболее удобным вариантом использованияlambda
функции. Например, при сортировке списка объектов:Поэтому я бы посоветовал сохранить использование лямбда-выражений для такого рода тривиальных операций, которые также не получают никакой выгоды от автоматической документации, предоставляемой путем присвоения имени функции.
источник
лямбда полезна для создания новых функций:
источник