С лямбда: C# и .NET | Лямбды

Содержание

Проблема с лямбда-датчиком на Honda Fit

Современные автомобили все чаще загружаются новыми технологиями, помимо комфорта использования, которые они могут обеспечить, технология также имеет преимущество в экономии топлива или снижении выбросов загрязняющих веществ, выбрасываемых нашими транспортными средствами. Это как раз тема нашей сегодняшней статьи, мы рассмотрим при проблемах лямбда-зонда на Хонда Фит , этот датчик также называют датчик кислорода играет важную функцию. Чтобы выяснить, сначала мы собираемся определить, для чего используется лямбда-зонд, а затем, каковы проблемы с лямбда-датчиком на Honda Fit и как их решить.

Что такое лямбда-задача на Honda Fit?

Итак, мы начинаем нашу страницу содержимого с благо лямбда-зонд на Honda Fit , мы сначала узнаем, какова функция этого зонда, а затем как он работает.

Роль лямбда-зонда на Honda Fit

Впервые разработанный Volvo в 1970-х годах, он начал появляться на наших автомобилях в 1990-х годах с первыми требованиями к выбросам EURO 1. Также называется датчик кислорода на Honda Fit

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

Процесс лямбда-зонда на Honda Fit

Прежде чем объяснять вам разные проблемы лямбда-зонда на Honda Fit , мы более подробно рассмотрим его функционирование, чтобы вы могли понять, как именно он работает, и, таким образом, более спокойно подумать об исправлении связанной с ним проблемы.
Как мы сообщали вам, лямбда-зонд выполняет функцию управление количеством кислорода в выхлопных газах . Можно наивно предположить, что эти данные рассчитаны до горения, но это наоборот. измеряется на выходе из двигателя . В стандарте EURO 1 до катализатора требовался только один лямбда-зонд, но с появлением более радикальных спецификаций теперь есть

2 лямбда-зонда, один до и один после катализатора . Преимущество состоит в том, чтобы получить более точные данные, скомпилировав два зонда. Эти данные отправляются в ЭБУ, который изменяет количество воздуха и бензина, впрыскиваемого в двигатель, для улучшения сгорания. .

Проблема с лямбда-датчиком на Honda Fit

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

Как узнать, является ли лямбда-зонд на Honda Fit HS

.
Важно знать, что лямбда-зонд, вообще говоря, срок службы 150 км , эти данные могут отличаться в зависимости от года выпуска вашего автомобиля Honda Fit, вашего вождения и исправности двигателя. Плохо ухаживаемый двигатель, выделяющий несгоревшие газы, может навсегда изменить ваш лямбда-зонд. Одна из подсказок, которая может

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

Как заменить лямбда-зонд на Хонда Фит?

И напоследок сосредоточимся на исправление проблем с лямбда-зондом на Honda Fit , описывая, как заменить лямбду Датчик.

Замену лямбда-зонда выполнить очень легко, и вы сможете сделать это самостоятельно, используя минимум инструментов и ноу-хау механики. А лямбда-зонд стоит от 25 до 50 € , лучше заменить 2 лямбда-зонда перед и после каталитического нейтрализатора, потому что, если один из них неисправен, второй рискует довольно быстро уронить вас. Для его замены потребуется поставь свой хонда фит на свечи и на уровне вашего катализатора открутите зонды, отсоедините их, снова подсоедините и прикрутите новые

. После повторного подключения у вас больше не должно быть проблем с лямбда-датчиком на Honda Fit.

Если вам нужны дополнительные учебные материалы по Honda Fit, перейдите на наш Honda Fit категория.

Проблема с лямбда-датчиком на Mitsubishi Mirage

Современные автомобили все чаще загружаются новыми технологиями, помимо комфорта использования, которые они могут обеспечить, технология также имеет преимущество в экономии топлива или сокращении выбросов загрязняющих веществ, выделяемых нашими автомобилями. Это как раз тема содержания нашей сегодняшней статьи, мы будем смотреть при проблемах лямбда-зонда на Митсубиси Мираж , этот датчик также называется датчик кислорода plays an necessary purpose. To find out, first, we are going to identify what a lambda probe is used for, then, what are the lambda sensor problems on Mitsubishi Mirage and how to fix them.

Какое значение имеет лямбда-функция на Mitsubishi Mirage?

Итак, мы начинаем нашу страницу содержимого с интерес лямбда-зонда на Митсубиси Мираж , мы сначала увидим, в чем задача этого зонда, а затем как он работает.

Роль лямбда-зонда на Mitsubishi Mirage

Впервые созданный Volvo в 1970-х годах, он начал появляться на наших автомобилях в 1990-х годах с первыми стандартами выбросов EURO 1. Также называется датчик кислорода на Mitsubishi Mirage , его цель — регулировать количество кислорода в выхлопных газах, это позволит блоку двигателя изменять топливно-воздушную смесь на уменьшить загрязнение, выбрасываемое автомобилем, и снизить расход топлива автомобилем.

Порядок действий лямбда-зонда на Митсубиси Мираж

Прежде чем объяснять вам разные проблемы лямбда-зонда на Mitsubishi Mirage , мы более подробно рассмотрим его функционирование, чтобы вы могли точно понять, как он работает, и, таким образом, более спокойно подумать об исправлении связанной с ним проблемы.
Как мы объясняли вам, лямбда-зонд выполняет функцию управление количеством кислорода в выхлопных газах . Можно было бы наивно подумать, что эти данные измеряются перед камерой сгорания, но это наоборот. измеряется на выходе из двигателя . Со стандартом EURO 1 до катализатора требовался только один лямбда-зонд, но с появлением более жестких стандартов теперь 2 лямбда-зонда, один до и один после катализатора . Интересно получить более точные данные, скомпилировав два зонда. Эти данные отправляются в ЭБУ, который регулирует количество воздуха и бензина, впрыскиваемого в блок двигателя, для улучшения сгорания.

.

Проблема с лямбда-датчиком на Mitsubishi Mirage

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

Как узнать, является ли лямбда-зонд на Mitsubishi Mirage HS

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

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

Как поменять лямбда-зонд на Митсубиси Мираж?

И, наконец, сконцентрируемся на исправление проблем с лямбда-зондом на Mitsubishi Mirage , подробно описав, как заменить лямбду Датчик.

Замену лямбда-зонда довольно просто выполнить, и у вас будет возможность сделать это самостоятельно, используя минимум инструментов и механических навыков. А лямбда-зонд стоит от 25 до 50 € , лучше заменить 2 лямбда-зонда перед и после каталитического нейтрализатора, потому что, если один из них неисправен, второй рискует быстро уронить вас. Для его замены потребуется поставь свой Mitsubishi Mirage на свечи и на уровне вашего катализатора открутите зонды, отсоедините их, снова подсоедините и прикрутите новые

. После повторного подключения у вас больше не должно возникнуть проблем с лямбда-датчиком на Mitsubishi Mirage.

Чтобы узнать больше о Mitsubishi Mirage, взгляните на Мицубиси Мираж категория.

Как использовать в Python лямбда-функции

В Python и других языках, таких как Java, C# и даже C++, в их синтаксис добавлены лямбда-функции, в то время как языки, такие как LISP или семейство языков ML, Haskell, OCaml и F#, используют лямбда-выражения.

Python-лямбды — это маленькие анонимные функции, подчиняющиеся более строгому, но более лаконичному синтаксису, чем обычные функции Python.

К концу этой статьи вы узнаете:

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

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

Эти сомнительные примеры будут противопоставляться лучшим подходам или альтернативам по мере прохождения статьи.

Все примеры, включенные в это руководство, были протестированы в Python 3.7.

Лямбда-исчисление

Лямбда-выражения в Python и других языках программирования имеют свои корни в лямбда-исчислении, модели вычислений, изобретенной Алонзо Черчем (Alonzo Church). Далее мы расскажем, когда появилось лямбда-исчисление и почему эта фундаментальная концепция появилась в экосистеме Python.

История

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

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

Функциональные языки берут свое начало в математической логике и лямбда-исчислении, в то время как императивные языки программирования охватывают основанную на состоянии модель вычислений, изобретенную Аланом Тьюрингом. Две модели вычислений, лямбда-исчисление и машины Тьюринга, могут быть переведены друг в друга. Эта эквивалентность известна как гипотеза Чёрча-Тьюринга.

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

Напротив, машина Тьюринга привела к императивному программированию, используемому в таких языках, как Fortran, C или Python.

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

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

Python по своей сути не является функциональным языком, но на раннем этапе он принял некоторые функциональные концепции. В январе 1994 года к языку были добавлены map(), filter(), reduce() и лямбда-оператор.

Первый пример

Вот несколько примеров, чтобы продемонстрировать функциональный стиль.

Функция тождества (identity function), функция, которая возвращает свой аргумент, выражается стандартным определением функции Python с использованием ключевого слова def следующим образом:

>>> def identity(x):
. ..   return x

identity() принимает аргумент x и возвращает его при вызове.

Если вы воспользуетесь лямбда-конструкцией, ваш код будет следующим:

>>> lambda x: x

В приведенном выше примере выражение состоит из:

  • Ключевое слово: lambda
  • Связанная переменная: x
  • Тело: х

Примечание. В контексте этой статьи связанная переменная является аргументом лямбда-функции.

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

Напишем немного более сложный пример, функцию, которая добавляет 1 к аргументу, следующим образом:

>>> lambda x: x + 1

Применим указанную выше функцию к аргументу, заключив функцию и ее аргумент в круглые скобки:

>>> (lambda x: x + 1)(2)
3

Сокращение — это стратегия лямбда-исчисления для вычисления значения выражения. Оно состоит из замены аргумента x на 2:

(lambda x: x + 1)(2) = lambda 2: 2 + 1
                     = 2 + 1
                     = 3

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

>>> add_one = lambda x: x + 1
>>> add_one(2)
3

Вышеупомянутая лямбда-функция эквивалентна написанию этого:

def add_one(x):
    return x + 1

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

>>> full_name = lambda first, last: f'Full name: {first.title()} {last.title()}'
>>> full_name('guido', 'van rossum')
'Full name: Guido Van Rossum'

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

Анонимные функции

Следующие термины могут использоваться взаимозаменяемо в зависимости от языка программирования:

  • Анонимные функции
  • Лямбда-функции
  • Лямбда-выражения
  • Лямбда-абстракции
  • Лямбда-форма
  • Функциональные литералы

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

В буквальном смысле, анонимная функция — это функция без имени. В Python анонимная функция создается с помощью ключевого слова lambda. Рассмотрим анонимную функцию с двумя аргументами, определенную с помощью лямбды, но не связанную с переменной.

>>> lambda x, y: x + y

Вышеприведенная функция определяет лямбда-выражение, которое принимает два аргумента и возвращает их сумму.

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

>>> _(1, 2)
3

В приведенном выше примере используется только функция интерактивного транслятора, представленная через символ подчеркивания (_).

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

Примечание. В интерактивном интерпретаторе подчеркивание (_) привязано к последнему вычисленному выражению.

Для получения более подробной информации об использовании этого специального символа в Python, посмотрите Значение подчеркивания в Python (The Meaning of Underscores in Python).

Другой шаблон, используемый в других языках, таких как JavaScript, — это немедленное выполнение лямбда-функции Python. Это называется выражением немедленного вызова функции (IIFE —  Immediately Invoked Function Expression, произносится «iffy»). Вот пример:

>>> (lambda x, y: x + y)(2, 3)
5

Вышеприведенная лямбда-функция определяется, а затем сразу вызывается с двумя аргументами (2 и 3). Возвращает значение 5, которое является суммой аргументов.

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

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

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

>>> high_ord_func = lambda x, func: x + func(x)
>>> high_ord_func(2, lambda x: x * x)
6
>>> high_ord_func(2, lambda x: x + 3)
7

Python содержит функции высшего порядка в виде встроенных функций или в стандартной библиотеке. Примеры функций высшего порядка map(), filter(), functools.reduce(), а также такие ключевые функции, как sort(), sorted(), min() и max(). Мы продемонстрируем использование лямбда-функции вместе с функциями высшего порядка в разделе «Соответствующее использование лямбда-выражений».

Лямбда и обычные функции

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

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

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

Функции

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

Модуль dis предоставляет функции для анализа байт-кода Python, сгенерированного компилятором Python:

>>> import dis
>>> add = lambda x, y: x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function <lambda> at 0x7f30c6ce9ea0>

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

Теперь посмотрим на обычный объект функции:

>>> import dis
>>> def add(x, y): return x + y
>>> type(add)
<class 'function'>
>>> dis.dis(add)
  1           0 LOAD_FAST                0 (x)
              2 LOAD_FAST                1 (y)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> add
<function add at 0x7f30c6ce9f28>

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

Traceback

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

>>> div_zero = lambda x: x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in <lambda>
ZeroDivisionError: division by zero

Трассировка исключения, возникшего при выполнении лямбда-функции, идентифицирует только функцию, вызывающую исключение, как <lambda> .

Вот то же исключение, вызванное в нормальной функции:

>>> def div_zero(x): return x / 0
>>> div_zero(2)
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in div_zero
ZeroDivisionError: division by zero

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

Синтаксис

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

  • Она может содержать только выражения и не может включать операторы в свое тело.
  • Она пишется как одна строка исполнения.
  • Она не поддерживает аннотации типов.
  • Она может быть немедленно вызвана (IIFE).

Отсутствие утверждений

Лямбда-функция не может содержать утверждения. В лямбда-функции такие операторы, как return, pass, assert или raise, вызовут исключение SyntaxError. Вот пример добавления assert к телу лямбды:

>>> (lambda x: assert x == 2)(2)
  File "<input>", line 1
    (lambda x: assert x == 2)(2)
                    ^
SyntaxError: invalid syntax

Этот надуманный пример демонстрирующий что с помощью assert, утверждается что параметр x имеет значение 2. Но интерпретатор выдает SyntaxError при синтаксическом анализе кода, который включает в себя утверждение assert в теле лямбда-выражения.

Одиночное выражение

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

>>> (lambda x:
... (x % 2 and 'odd' or 'even'))(3)
'odd'

Приведенный выше пример возвращает строку «odd», если лямбда-аргумент нечетный, и «even», когда аргумент четный. Он распространяется на две строки, поскольку содержится в скобках, но остается одним выражением.

Аннотации типов

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

def full_name(first: str, last: str) -> str:
    return f'{first.title()} {last.title()}'

Любая ошибка типа в full_name() может быть обнаружена такими инструментами, как mypy или pyre, тогда как в эквивалентной лямбда-функцией сразу будет ошибка SyntaxError во время выполнения:

>>> lambda first: str, last: str: first.title() + " " + last.title() -> str
  File "<stdin>", line 1
    lambda first: str, last: str: first.title() + " " + last.title() -> str

SyntaxError: invalid syntax

IIFE

Вы уже видели несколько примеров немедленного запуска функции:

>>> (lambda x: x * x)(3)
9

Вне интерпретатора эта функция, вероятно, не будет используется на практике. Это прямое следствие того, что лямбда-функция вызывается сразу после того, как она определена. Но, это конструкция позволяет передать определение лямбды в функцию более высокого порядка, например map(), filter() или functools.reduce().

Аргументы

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

  • Позиционные аргументы
  • Именованные аргументы (иногда называемые ключевыми аргументами)
  • Переменный список аргументов (часто называемый varargs)
  • Переменный список аргументов ключевых слов
  • Аргументы только для ключевых слов

Следующие примеры иллюстрируют опции, доступные для передачи аргументов в лямбда-выражения:

>>> (lambda x, y, z: x + y + z)(1, 2, 3)
6
>>> (lambda x, y, z=3: x + y + z)(1, 2)
6
>>> (lambda x, y, z=3: x + y + z)(1, y=2)
6
>>> (lambda *args: sum(args))(1,2,3)
6
>>> (lambda **kwargs: sum(kwargs. values()))(one=1, two=2, three=3)
6
>>> (lambda x, *, y=0, z=0: x + y + z)(1, y=2, z=3)
6

Декораторы

В Python декоратор — это реализация шаблона, который позволяет добавить поведение к функции или классу. Обычно это выражается синтаксисом @decorator с префиксом функции. Вот пример:

def some_decorator(f):
    def wraps(*args):
        print(f"Calling function '{f.__name__}'")
        return f(args)
    return wraps

@some_decorator
def decorated_function(x):
    print(f"With argument '{x}'")

В приведенном выше примере some_decorator() — это функция, которая добавляет поведение к decorated_function(), так что при вызове decorated_function(2) получается следующий результат:

Calling function 'decorated_function'
With argument 'Python'

decorated_function() печатает только With argument ‘Python’, но декоратор добавляет дополнительное поведение, которое также печатает Calling function ‘decorated_function’.

Декоратор может быть применен к лямбде. Хотя невозможно декорировать лямбду с помощью синтаксиса @decorator, декоратор — это просто функция, поэтому он может вызывать функцию лямбда:

 1 # Defining a decorator
 2 def trace(f):
 3     def wrap(*args, **kwargs):
 4         print(f"[TRACE] func: {f.__name__}, args: {args}, kwargs: {kwargs}")
 5         return f(*args, **kwargs)
 6 
 7     return wrap
 8 
 9 # Applying decorator to a function
10 @trace
11 def add_two(x):
12     return x + 2
13 
14 # Calling the decorated function
15 add_two(3)
16 
17 # Applying decorator to a lambda
18 print((trace(lambda x: x ** 2))(3))

add_two(), декорирована @trace в строке 11, вызывается с аргументом 3 в строке 15. В отличие от этого, в строке 18 сразу же включается лямбда-функция и встраивается в вызов метода trace(), декоратора. Когда вы выполняете код выше, вы получаете следующее:

[TRACE] func: add_two, args: (3,), kwargs: {}
[TRACE] func: <lambda>, args: (3,), kwargs: {}
9

Посмотрите, как, как вы уже видели, имя лямбда-функции выглядит как <lambda>, тогда как add_two четко идентифицировано как обычная функция.

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

list(map(trace(lambda x: x*2), range(3)))

Первый аргумент map() — это лямбда, которая умножает свой аргумент на 2. Эта лямбда декорирована trace(). При выполнении приведенный выше пример выводит следующее:

[TRACE] Calling <lambda> with args (0,) and kwargs {}
[TRACE] Calling <lambda> with args (1,) and kwargs {}
[TRACE] Calling <lambda> with args (2,) and kwargs {}
[0, 2, 4]

Результат [0, 2, 4] представляет собой список, полученный умножением каждого элемента range(3). range(3) является простым списком [0, 1, 2].

Замыкание

Замыкание — это функция, в которой каждая свободная переменная, кроме параметров, используемых в этой функции, привязана к определенному значению, определенному в рамках области видимости этой функции. В сущности, замыкания определяют среду, в которой они работают, и поэтому могут вызываться из любого места. Более простое определение замыкания это когда функции более низшего порядка имеют доступ к переменным функции более высшего порядка.

Понятия лямбды и замыкания не обязательно связаны, хотя лямбда-функции могут быть замыканиями так же, как обычные функции также могут быть замыканиями. Некоторые языки имеют специальные конструкции для замыкания или лямбды (например, Groovy с анонимным блоком кода в качестве объекта Closure) или лямбда-выражения (например, лямбда-выражения Java с ограниченным параметром для замыкания).

Вот пример замыкания, построенное с помощью обычной функции Python:

 1 def outer_func(x):
 2     y = 4
 3     def inner_func(z):
 4         print(f"x = {x}, y = {y}, z = {z}")
 5         return x + y + z
 6     return inner_func
 7 
 8 for i in range(3):
 9     closure = outer_func(i)
10     print(f"closure({i+5}) = {closure(i+5)}")

outer_func() возвращает inner_func(), вложенную функцию, которая вычисляет сумму трех аргументов:

  • x передается в качестве аргумента outer_func().
  • y является локальной переменной для outer_func().
  • z аргумент, передаваемый в inner_func().

Чтобы продемонстрировать поведение outer_func() и inner_func(), outer_func() вызывается три раза в цикле for, который выводит следующее:

x = 0, y = 4, z = 5
closure(5) = 9
x = 1, y = 4, z = 6
closure(6) = 11
x = 2, y = 4, z = 7
closure(7) = 13

В строке 9 кода inner_func(), возвращаемый вызовом outer_func(), привязывается к имени замыкания. В строке 5 inner_func() захватывает x и y, потому что он имеет доступ к своей области видимости, так что при вызове замыкания он может работать с двумя свободными переменными x и y.

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

def outer_func(x):
    y = 4
    return lambda z: x + y + z

for i in range(3):
    closure = outer_func(i)
    print(f"closure({i+5}) = {closure(i+5)}")

Когда вы выполняете приведенный выше код, вы получаете следующий вывод:

closure(5) = 9
closure(6) = 11
closure(7) = 13

В строке 6 outer_func() возвращает лямбду и присваивает ее переменную замыкания. В строке 3 тело лямбда-функции ссылается на x и y. Переменная y доступна во время определения, тогда как x определяется во время выполнения, когда вызывается outer_func().

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

Время оценки

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

Сначала протестируем сценарий, используя обычную функцию:

 1 >>> def wrap(n):
 2 ...     def f():
 3 ...         print(n)
 4 ...     return f
 5 ...
 6 >>> numbers = 'one', 'two', 'three'
 7 >>> funcs = []
 8 >>> for n in numbers:
 9 . ..     funcs.append(wrap(n))
10 ...
11 >>> for f in funcs:
12 ...     f()
13 ...
14 one
15 two
16 three

В нормальной функции n вычисляется во время определения, в строке 9, когда функция добавляется в список: funcs.append (wrap (n)).

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

 1 >>> numbers = 'one', 'two', 'three'
 2 >>> funcs = []
 3 >>> for n in numbers:
 4 ...     funcs.append(lambda: print(n))
 5 ...
 6 >>> for f in funcs:
 7 ...     f()
 8 ...
 9 three
10 three
11 three

Неожиданный результат возникает из-за того, что свободная переменная n, как она реализована, связана во время выполнения лямбда-выражения. Лямбда-функция Python в строке 4 является замыканием, которое захватывает n, свободную переменную, ограниченную во время выполнения. Во время выполнения при вызове функции f из строки 7 значение n равно three.

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

 1 >>> numbers = 'one', 'two', 'three'
 2 >>> funcs = []
 3 >>> for n in numbers:
 4 ...     funcs.append(lambda n=n: print(n))
 5 ...
 6 >>> for f in funcs:
 7 ...     f()
 8 ...
 9 one
10 two
11 three

Лямбда ведет себя как нормальная функция в отношении аргументов. Следовательно, лямбда-параметр может быть инициализирован значением по умолчанию: параметр n принимает значение n по умолчанию для внешнего n. Лямбда может бы быть записана как lambda x=n: print(x) и вернуть такой же результат.

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

Тестирование Лямбды

Лямбды можно тестировать аналогично обычным функциям. Можно использовать как unittest, так и doctest.

unittest

Модуль unittest обрабатывает лямбда-функции Python аналогично обычным функциям:

import unittest

addtwo = lambda x: x + 2

class LambdaTest(unittest.TestCase):
    def test_add_two(self):
        self.assertEqual(addtwo(2), 4)

    def test_add_two_point_two(self):
        self.assertEqual(addtwo(2.2), 4.2)

    def test_add_three(self):
        # Should fail
        self.assertEqual(addtwo(3), 6)

if __name__ == '__main__':
    unittest. main(verbosity=2)

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

$ python lambda_unittest.py
test_add_three (__main__.LambdaTest) ... FAIL
test_add_two (__main__.LambdaTest) ... ok
test_add_two_point_two (__main__.LambdaTest) ... ok

======================================================================
FAIL: test_add_three (__main__.LambdaTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "lambda_unittest.py", line 18, in test_add_three
    self. assertEqual(addtwo(3), 6)
AssertionError: 5 != 6

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1)

Как и ожидалось, у нас есть два успешных тестовых примера и один сбой для test_add_three: результат равен 5, но ожидаемый результат равен 6. Этот сбой вызван преднамеренной ошибкой в тестовом примере. Изменение ожидаемого результата с 6 на 5 удовлетворит все тесты для LambdaTest.

doctest

Модуль doctest извлекает интерактивный код Python из docstring для выполнения тестов. Хотя синтаксис лямбда-функций Python не поддерживает типичную docstring, можно присвоить строку элементу __doc__ именованной переменной лямбды:

addtwo = lambda x: x + 2
addtwo. __doc__ = """Add 2 to a number.
    >>> addtwo(2)
    4
    >>> addtwo(2.2)
    4.2
    >>> addtwo(3) # Should fail
    6
    """

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)

Тест doctest в комментарии к функции lambda addtwo() описывает те же тесты, что и в предыдущем разделе.

Когда вы выполняете тесты с помощью doctest.testmod(), вы получаете следующее:

$ python lambda_doctest.py
Trying:
    addtwo(2)
Expecting:
    4
ok
Trying:
    addtwo(2.2)
Expecting:
    4.2
ok
Trying:
    addtwo(3) # Should fail
Expecting:
    6
**********************************************************************
File "lambda_doctest.py", line 16, in __main__.addtwo
Failed example:
    addtwo(3) # Should fail
Expected:
    6
Got:
    5
1 items had no tests:
    __main__
**********************************************************************
1 items had failures:
   1 of   3 in __main__. addtwo
3 tests in 2 items.
2 passed and 1 failed.
***Test Failed*** 1 failures.

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

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

Злоупотребления лямбда-выражениями

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

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

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

  • Он не следует руководству по стилю Python (PEP 8)
  • Код выглядит громоздким и трудно читаемым.

Возникновение исключения

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

>>> def throw(ex): raise ex
>>> (lambda: throw(Exception('Something bad happened')))()
Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    File "<stdin>", line 1, in <lambda>
    File "<stdin>", line 1, in throw
Exception: Something bad happened

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

Загадочный стиль

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

Следующий лямбда-пример содержит несколько неудачных стилей:

>>> (lambda _: list(map(lambda _: _ // 2, _)))([1,2,3,4,5,6,7,8,9,10])
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

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

>>> (lambda some_list: list(map(lambda n: n // 2,
                                some_list)))([1,2,3,4,5,6,7,8,9,10])
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

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

>>> def div_items(some_list):
      div_by_two = lambda n: n // 2
      return map(div_by_two, some_list)
>>> list(div_items([1,2,3,4,5,6,7,8,9,10])))
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]

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

Классы Python

Вы можете, но не должны писать методы класса как лямбда-функции Python. Следующий пример является совершенно допустимым кодом Python, но демонстрирует нетрадиционный код, основанный на лямбде. Например, вместо реализации __str__ как обычной функции он использует лямбду. Аналогично, brand и year — это свойства, также реализованные с помощью лямбда-функций вместо обычных функций или декораторов:

class Car:
    """Car with methods as lambda functions."""
    def __init__(self, brand, year):
        self.brand = brand
        self. year = year

    brand = property(lambda self: getattr(self, '_brand'),
                     lambda self, value: setattr(self, '_brand', value))

    year = property(lambda self: getattr(self, '_year'),
                    lambda self, value: setattr(self, '_year', value))

    __str__ = lambda self: f'{self.brand} {self.year}'  # 1: error E731

    honk = lambda self: print('Honk!')     # 2: error E731

При запуске такого инструмента, как flake8, инструмент обеспечения соблюдения стилей, будут отображаться следующие ошибки для __str__ и honk:

E731 do not assign a lambda expression, use a def

Хотя flake8 не указывает на проблему использования лямбда-функций в свойствах, их трудно читать и они подвержены ошибкам из-за использования нескольких строк, таких как _brand и _year.

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

def __str__(self):
    return f'{self.brand} {self.year}'

brand будет написана следующим образом:

@property
def brand(self):
    return self._brand

@brand.setter
def brand(self, value):
    self._brand = value

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

Правильное использование лямбда-выражений

Лямбды в Python, как правило, являются предметом споров. Некоторые аргументы против лямбды в Python:

  • Проблемы с читабельностью
  • Наложение функционального мышления
  • Тяжелый синтаксис с ключевым словом lambda

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

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

Классические функциональные конструкции

Лямбда-функции регулярно используются со встроенными функциями map() и filter(), а также functools.reduce(), представленными в модуле functools. Следующие три примера являются соответствующими иллюстрациями использования этих функций с лямбда-выражениями в качестве компаньонов:

>>> list(map(lambda x: x. upper(), ['cat', 'dog', 'cow']))
['CAT', 'DOG', 'COW']
>>> list(filter(lambda x: 'o' in x, ['cat', 'dog', 'cow']))
['dog', 'cow']
>>> from functools import reduce
>>> reduce(lambda acc, x: f'{acc} | {x}', ['cat', 'dog', 'cow'])
'cat | dog | cow'

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

Ключевые функции

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

  • sort(): метод списка
  • sorted()min()max(): встроенные функции
  • nlargest() and nsmallest(): в модуле алгоритма очереди кучи heapq

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

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

>>> ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100']
>>> print(sorted(ids)) # Lexicographic sort
['id1', 'id2', 'id30', 'id3', 'id22', 'id100']
>>> sorted_ids = sorted(ids, key=lambda x: int(x[2:])) # Integer sort
>>> print(sorted_ids)
['id1', 'id2', 'id3', 'id22', 'id30', 'id100']

UI Фреймворки

UI фреймворки, такие как Tkinter, wxPython или . NET Windows Forms с IronPython, используют лямбда-функции для отображения действий в ответ на события пользовательского интерфейса.

Простая программа Tkinter, представленная ниже, демонстрирует использование лямбды, назначенной команде кнопки Reverse:

import tkinter as tk
import sys

window = tk.Tk()
window.grid_columnconfigure(0, weight=1)
window.title("Lambda")
window.geometry("300x100")
label = tk.Label(window, text="Lambda Calculus")
label.grid(column=0, row=0)
button = tk.Button(
    window,
    text="Reverse",
    command=lambda: label.configure(text=label.cget("text")[::-1]),
)
button.grid(column=0, row=1)
window.mainloop()

Нажатие кнопки «Reverse» запускает событие, которое запускает лямбда-функцию, изменяя метку с Lambda Calculus на suluclaC adbmaL *:

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

Интерпритатор Python

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

timeit

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

>>> from timeit import timeit
>>> timeit("factorial(999)", "from math import factorial", number=10)
0. 0013087529951008037

Когда инструкция передается в виде строки, timeit() нужен полный контекст. В приведенном выше примере это обеспечивается вторым аргументом, который устанавливает среду, необходимую основной функции для синхронизации. В противном случае возникнет исключение NameError.

Другой подход — использовать лямбду:

>>> from math import factorial
>>> timeit(lambda: factorial(999), number=10)
0.0012704220062005334

Это решение чище, более читабельно и быстрее вводится в интерпретаторе.

Monkey Patching

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

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

from contextlib import contextmanager
import secrets

def gen_token():
    """Generate a random token."""
    return f'TOKEN_{secrets.token_hex(8)}'

@contextmanager
def mock_token():
    """Context manager to monkey patch the secrets.token_hex
    function during testing.
    """
    default_token_hex = secrets.token_hex
    secrets.token_hex = lambda _: 'feedfacecafebeef'
    yield
    secrets.token_hex = default_token_hex

def test_gen_key():
    """Test the random token."""
    with mock_token():
        assert gen_token() == f"TOKEN_{'feedfacecafebeef'}"

test_gen_key()

Диспетчер контекста помогает изолировать операцию monkey patching функцию из стандартной библиотеки (в этом примере secrets). Лямбда назначенная для secrets.token_hex (), заменяет поведение по умолчанию, возвращая статическое значение.

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

Среды модульного тестирования, такие как unittest и pytest, поднимают эту концепцию на более высокий уровень сложности.

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

import secrets

def gen_token():
    return f'TOKEN_{secrets. token_hex(8)}'

def test_gen_key(monkeypatch):
    monkeypatch.setattr('secrets.token_hex', lambda _: 'feedfacecafebeef')
    assert gen_token() == f"TOKEN_{'feedfacecafebeef'}"

С помощью pytest secretts.token_hex() перезаписывается лямбда-выражением, которое будет возвращать детерминированное значение feedfacecafebeef, позволяющее подтвердить правильность теста. monkeypatch позволяет вам контролировать область переопределения. В приведенном выше примере при вызове secretts.token_hex() в последующих тестах без использования monkey patching будет выполняться обычная реализация этой функции.

Выполнение теста pytest дает следующий результат:

$ pytest test_token.py -v
============================= test session starts ==============================
platform linux -- Python 3. 7.2, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
cachedir: .pytest_cache
rootdir: /home/andre/AB/tools/bpython, inifile:
collected 1 item

test_token.py::test_gen_key PASSED                                       [100%]

=========================== 1 passed in 0.01 seconds ===========================

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

Альтернативы лямбдам

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

Функции более высокого порядка, такие как map(), filter() и functools.reduce(), могут быть преобразованы в более элегантные формы с небольшими изменениями, в частности, со списком или генератором выражений.

Map

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

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

>>> list(map(lambda x: x.capitalize(), ['cat', 'dog', 'cow']))
['Cat', 'Dog', 'Cow']

Вам необходимо вызвать list() для преобразования итератора, возвращаемого map(), в расширенный список, который можно отобразить в интерпретаторе оболочки Python.

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

>>> [x. capitalize() for x in ['cat', 'dog', 'cow']]
['Cat', 'Dog', 'Cow']

Filter

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

>>> even = lambda x: x%2 == 0
>>> list(filter(even, range(11)))
[0, 2, 4, 6, 8, 10]

Обратите внимание, что filter() возвращает итератор, поэтому необходимо вызывать list, который создает список с заданным итератором.

Реализация, использующая конструкцию генератора списка, дает следующее:

>>> [x for x in range(11) if x%2 == 0]
[0, 2, 4, 6, 8, 10]

Reduce

Начиная с Python 3, Reduce() превратился из встроенной функции в функцию модуля functools. Что касается map() и filter(), его первые два аргумента являются соответственно функцией и итерируемым списком. Он также может принимать инициализатор в качестве третьего аргумента, который используется в качестве начального значения результирующего аккумулятора. Для каждого итерируемого элемента reduce() применяет функцию и накапливает результат, который возвращается, когда итерация исчерпана.

Чтобы применить reduce() к списку пар и вычислить сумму первого элемента каждой пары, вы можете написать так:

>>> import functools
>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> functools. reduce(lambda acc, pair: acc + pair[0], pairs, 0)
6

Более идиоматический подход, использующий выражение генератора в качестве аргумента для sum() в следующем примере:

>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> sum(x[0] for x in pairs)
6

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

>>> pairs = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> sum(x for x, _ in pairs)
6

Использование символа подчеркивания (_) является соглашением Python, указывающим, что вы можете игнорировать второе значение пары.

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

Лямбда — это питон или нет?

PEP 8, который является руководством по стилю для кода Python, гласит:

Всегда используйте оператор def вместо оператора присваивания, который связывает лямбду непосредственно с идентификатором. (Источник)

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

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

Заключение

Теперь вы знаете, как использовать лямбды в Python и можете:

  • Написать лямбду и использовать анонимные функции
  • Мудро выбирать между лямбдами или обычными функциями
  • Избегать чрезмерного использования лямбд
  • Использовать лямбды с функциями высшего порядка или ключевыми функциями Python

Если у вас есть склонность к математике, вы можете повеселиться, исследуя увлекательный мир лямбда-исчисления (lambda calculus).

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

Оригинальная статья:  Andre Burgaud  How to Use Python lambda Functions

Была ли вам полезна эта статья?


Лямбда-С, КЭ — Росагрохим

Норма расхода препарата, л/га Культура, обрабатываемый объект Вредный объект Способ, время, особенности применения препарата Срок ожидания (кратность обработки)
0,2 Пшеница Хлебные жуки, трипсы, блошки, цикадки Опрыскивание в период вегетации. Расход рабочей жидкости – 200-400 л/га 20(1)
0,15 Клоп вредная черепашка, тли, пьявица 20(2)
0,15-0,2 Ячмень Мухи, пьявица, цикадки, трипсы, стеблевые пилильщики, тли
0,4 Яблоня Яблонная плодожорка, листовёртки, клещи Опрыскивание в период вегетации. Расход рабочей жидкости- 1000-1500 л/га 30(2)
0,1-0,15 Яблонный цветоед Опрыскивание до цветения. Расход рабочей жидкости – 800-1200 л/га 30(1)
0,1 Горчица (кроме горчицы на масло) Рапсовый цветоед Опрыскивание в период вегетации. Расход рабочей жидкости – 200-400 л/га 20(1)
0,4 Вишня (маточники) Паутинный клещ, тли, листовертки Опрыскивание в период вегетации. Расход рабочей жидкости – 800-1200 л/га -(2)
0,5 Земляника (маточники) Опрыскивание в период вегетации. Расход рабочей жидкости – 400-500 л/га
0,4 Малина (маточники) Опрыскивание в период вегетации. Расход рабочей жидкости – 600-1200 л/га
0,3-0,4 Смородина (маточники)
0,3 Крыжовник (маточники) Паутинный клещ, тли, пилильщики
0,1 Картофель Колорадский жук Опрыскивание в период вегетации. Расход рабочей жидкости – 200-400 л/га 14(2)
Капуста Капустная совка, белянки, капустная моль, крестоцветные блошки 20(1)
0,2-0,4 Неплодоносящие сады, лесозащитные полосы Американская белая бабочка Опрыскивание в период вегетации. Расход рабочей жидкости- 1000-1500 л/га. Срок для сбора дикорастущих грибов и ягод на обработанных территориях-30 дней. Срок возможного пребывания людей на обработанных площадях не ранее 7 дней после обработки -(1)
0,32-0,48 Виноград Листовёртки, клещи Опрыскивание в период вегетации. Расход рабочей жидкости- 600-1000 л/га. 10(2)
0,1-0,15 Рапс Рапсовый цветоед Опрыскивание в период вегетации. Расход рабочей жидкости – 200-400 л/га 20(2)
Лён-долгунец Блошки Опрыскивание в период вегетации. Расход рабочей жидкости – 100-200 л/га -(2)
0,15 Люцерна Клопы, тли, долгоносики, листоблошки, толстоножка люцерновая Опрыскивание в период вегетации. Расход рабочей жидкости – 200-400 л/га
0,1-0,15 Пастбища, участки заселенные саранчовыми, дикая растительность Саранчовые нестадные Опрыскивание в период развития личинок. Расход рабочей жидкости – 200-400 л/га. Срок для сбора дикорастущих грибов и ягод на обработанных территориях-30 дней. Срок возможного пребывания людей на обработанных площадях не ранее 7 дней после обработки -(1)
Саранчовые стадные (личинки младших возрастов)
0,4 Саранчовые стадные (личинки старших возрастов)

Лямбда — С, КЭ — инсектицид, 5 л, АгроХим Инвест Россия

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

Действующее вещество: 50 г/л лямбда-цигалотрина

Форма препарата: концентрат эмульсии

— защита широкого спектра культур от важнейших вредителей, в т. ч. взрослых клещей

— действует немедленно после обработки

— оказывает быстрое парализующее действие на насекомых (нокдаун-эффект)

— период защитного действия от 1 до 3-х недель при нормальных условиях

— высокая эффективность против вредителей в сочетании с невысокой стоимостью обработки

— не обладает фитотоксичностью при рекомендованных нормах расхода

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

Регламент применения:

Норма расхода препарата, л/га

Культура

Вредный объект

Способ, время, особенности применения препарата

Срок ожидания (кратность обработки)

0,2

Пшеница

Хлебные жуки, трипсы, блошки, цикадки

Опрыскивание в период вегетации. Расход рабочей жидкости — 200-400 л/га

20(1)

0,15

Клоп вредная черепашка, тли, пьявица

20(2)

0,15-0,2

Ячмень

Мухи, пьявица, цикадки, трипсы, стеблевые пилильщики, тли

0,4

Яблоня

Яблонная плодожорка, листовёртки, клещи

Опрыскивание в период вегетации. Расход рабочей жидкости- 1000-1500 л/га

30(2)

0,1-0,15

Яблонный цветоед

Опрыскивание до цветения. Расход рабочей жидкости — 800-1200 л/га

30(1)

0,1

Горчица (кроме горчицы на масло)

Рапсовый цветоед

Опрыскивание в период вегетации. Расход рабочей жидкости — 200-400 л/га

20(1)

0,4

Вишня (маточники)

Паутинный клещ, тли, листовертки

Опрыскивание в период вегетации. Расход рабочей жидкости — 800-1200 л/га

-(2)

0,5

Земляника (маточники)

Опрыскивание в период вегетации. Расход рабочей жидкости — 400-500 л/га

0,4

Малина (маточники)

Опрыскивание в период вегетации. Расход рабочей жидкости — 600-1200 л/га

0,3-0,4

Смородина (маточники)

0,3

Крыжовник (маточники)

Паутинный клещ, тли, пилильщики

0,1

Картофель

Колорадский жук

Опрыскивание в период вегетации. Расход рабочей жидкости — 200-400 л/га

14(2)

Капуста

Капустная совка, белянки, капустная моль, крестоцветные блошки

20(1)

0,2-0,4

Неплодоносящие сады, лесозащитные полосы

Американская белая бабочка

Опрыскивание в период вегетации. Расход рабочей жидкости- 1000-1500 л/га. Срок для сбора дикорастущих грибов и ягод на обработанных территориях-30 дней. Срок возможного пребывания людей на обработанных площадях не ранее 7 дней после обработки

-(1)

0,32-0,48

Виноград

Листовёртки, клещи

Опрыскивание в период вегетации. Расход рабочей жидкости- 600-1000 л/га.

10(2)

0,1-0,15

Рапс

Рапсовый цветоед

Опрыскивание в период вегетации. Расход рабочей жидкости — 200-400 л/га

20(2)

Лён-долгунец

Блошки

Опрыскивание в период вегетации. Расход рабочей жидкости — 100-200 л/га

-(2)

0,15

Люцерна

Клопы, тли, долгоносики, листоблошки, толстоножка люцерновая

Опрыскивание в период вегетации. Расход рабочей жидкости — 200-400 л/га

0,1-0,15

Пастбища, участки заселенные саранчовыми, дикая растительность

Саранчовые нестадные

Опрыскивание в период развития личинок. Расход рабочей жидкости — 200-400 л/га. Срок для сбора дикорастущих грибов и ягод на обработанных территориях-30 дней. Срок возможного пребывания людей на обработанных площадях не ранее 7 дней после обработки

-(1)

Саранчовые стадные (личинки младших возрастов)

0,4

Саранчовые стадные (личинки старших возрастов)

Обманка лямбда-зонда.

Кому это нужно
Имитация нормальной работы каталитического нейтрализатора – назначение обманки для второго датчика остаточного кислорода. В результате ее установки ЭБУ, независимо от состояния катализатора, получает с лямбда-зонда электрический сигнал о допустимом содержании CO в выхлопных газах.

Когда может потребоваться обманка

Катализатор может разрушиться, забиться сажей при некачественном топливе, просто потерять свои свойства. В таком случае второй лямбда-зонд отправит на ЭБУ сигнал о неисправном состоянии системы очистки выхлопных газов. Загорится сигнал «CHECK».

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

Катализатор – устройство не из дешевых. Не всегда есть в наличии соответствующая марка. Чтобы автомобиль не простаивал, остается только провести ЭБУ установкой обманки.

Два основных типа

Механическая обманка – это стальная вставка, которая вворачивается в катализатор в место лямбда-зонда. А уже в нее устанавливается сам датчик. Обманка сама содержит катализатор, который нейтрализует выхлопные газы, поступающие в нее в небольших количествах. Датчик кислорода измеряет содержание CO в ограниченном потоке выхлопных газов. Такая обманка является рабочим мини-макетом нейтрализатора выхлопных газов автомобиля.

Еще один вид механической обманки для автомобилей класса Е-3 – «пустая» обманка. В ее пустотелом корпусе проделано отверстие диаметром 2-3 мм. Лямбда-зонд, ввернутый в нее, выдает сигнал, соответствующий исправному состоянию катализатора.

Электронный эмулятор – устройство, подключаемое в разъем датчика кислорода. Он имитирует не только исправную работу катализатора, но и самого лямбда-зонда. Часто используется в случаях, когда не понятно, что является причиной появления ошибки.

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

Установка любого типа обманки не занимает больше 10-15 мин, может быть выполнена любым водителем самостоятельно.

Возможность перепрошивки ЭБУ используется редко. Хотя несложно изменить в программе тарировку датчика, сместив точку «исправно» на графике напряжений.

Вмешательство в программное обеспечение может отрицательно проявить себя при обновлении прошивок ЭБУ.

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

Лямбда-зонд в автомобиле: для чего нужен, последствия поломки

Что такое лямбда зонд?

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

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

Для чего нужен лямбда зонд?

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

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

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

%rtb-4%

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

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

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

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

%rtb-4%

Последствия поломки лямбда зонда?

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

Также существует ряд причин, способных вывести лямбда зонд из строя. К примеру, механизм может сломаться лишь частично, а именно – лямбда зонд продолжает работу, однако точность показаний резко падает. Лямбда зонд также может перестать активизироваться при определенной температуре. В любом случае, установить точную причину поломки может только специалист. Стоит отметить, что если лямбда зонд окончательно вышел из строя, то менять его нужно только на аналогичный механизм. В противном случае бортовой компьютер может просто не принимать его сигналы.

В случае, если отказывают сразу два датчика, то автомобиль может полностью выйти из строя. Единственный вариант передвижения, который остается в таком случае – это буксир или эвакуатор. Стоит помнить, что лямбда зонд чрезвычайно чувствителен к поломкам. Его могут вывести из строя некачественные поршневые кольца, сложный состав топлива и пропуски зажигания. В первую очередь, усугубить поломку может использование этилированного топлива, которое благодаря содержащемуся в нем свинцу выводит из строя платиновые электроды. Достаточно пару раз заправиться таким бензином, чтобы окончательно разрушить лямбда зонд.

Что такое катализатор в автомобиле?

Признаки забитого или разрушенного катализатора машины. Методы диагностирования неисправностей катализатора

AWS Lambda — бессерверные вычисления

Обработка данных

AWS Lambda можно использовать для выполнения кода в ответ на триггеры, такие как изменения данных, сдвиги в состоянии системы или действия пользователей. Lambda может напрямую запускаться сервисами AWS, такими как S3, DynamoDB, Kinesis, SNS и CloudWatch, может подключаться к существующим файловым системам EFS или может быть организован в рабочие процессы с помощью AWS Step Functions. Это позволяет создавать различные системы бессерверной обработки данных в реальном времени.

Обработка файлов в реальном времени

Amazon S3 можно использовать для запуска AWS Lambda для обработки данных сразу после загрузки. Вы также можете напрямую подключиться к существующей файловой системе Amazon EFS, что обеспечивает массовый параллельный общий доступ для крупномасштабной обработки файлов. Например, вы можете использовать Lambda для эскизов изображений, перекодирования видео, индексных файлов, обработки журналов, проверки содержимого, а также агрегирования и фильтрации данных в режиме реального времени.

The Seattle Times использует AWS Lambda для изменения размера изображений для просмотра на различных устройствах, таких как настольные компьютеры, планшеты и смартфоны. Прочитать пример использования »

Обработка потоков в реальном времени

AWS Lambda и Amazon Kinesis можно использовать для обработки потоковых данных в реальном времени для отслеживания активности приложений, обработки заказов транзакций, анализа потока кликов, очистки данных, создания показателей, фильтрации журналов, индексации, анализа социальных сетей, а также телеметрии данных устройств IoT и замер.

Localytics обрабатывает миллиарды точек данных в режиме реального времени и использует Lambda для обработки исторических и оперативных данных, хранящихся в S3 или передаваемых из Kinesis. Прочитать пример использования »

Машинное обучение

AWS Lambda можно использовать для предварительной обработки данных перед их передачей в модель машинного обучения.Имея Lambda-доступ к EFS, вы также можете использовать свою модель для прогнозирования в масштабе без необходимости выделять или управлять какой-либо инфраструктурой.

«В Aible мы фокусируемся на предоставлении самых мощных технологий искусственного интеллекта с минимально возможными эксплуатационными расходами. Поэтому мы используем AWS Lambda и Serverless для обучения машинному обучению и прогнозирования. Благодаря бессерверному использованию мы можем выполнять широкий спектр рабочих нагрузок машинного обучения с меньшими затратами. эффективно, используя при этом большие вычислительные ресурсы, необходимые для быстрой итерации и масштабирования, чтобы создать ИИ для оптимального воздействия на бизнес.»

Род Баттерс, технический директор — Aible


Бэкэнд

Вы можете создавать бессерверные серверные ВМ с помощью AWS Lambda для обработки веб-запросов, мобильных приложений, Интернета вещей (IoT) и сторонних API-запросов. Воспользуйтесь преимуществами согласованных средств управления производительностью Lambda, таких как несколько конфигураций памяти и Provisioned Concurrency, для создания чувствительных к задержкам приложений в любом масштабе.

Веб-приложения

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

Серверные модули Интернета вещей

Вы можете создавать бессерверные серверные ВМ с помощью AWS Lambda для обработки веб-запросов, мобильных приложений, Интернета вещей (IoT) и сторонних API-запросов.

Мобильные серверные части

AWS Lambda упрощает создание разнообразных персонализированных приложений. Вы можете создавать серверные части с помощью AWS Lambda и Amazon API Gateway для аутентификации и обработки запросов API. Используйте AWS Amplify, чтобы легко интегрировать серверную часть с интерфейсами iOS, Android, Web и React Native.

Bustle использует бессерверный бэкэнд для своего приложения и веб-сайтов Bustle iOS, используя AWS Lambda и Amazon API Gateway. Бессерверные архитектуры позволяют Bustle никогда не заниматься управлением инфраструктурой, поэтому каждый инженер может сосредоточиться на создании новых функций и внедрении инноваций. Прочитать пример использования »

Что такое AWS Lambda? — AWS Lambda

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

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

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

Вы можете вызывать свои Lambda-функции с помощью Lambda API, или Lambda может запускать ваши функции в ответ на события из других сервисов AWS. Например, вы можете использовать Lambda для:

  • Создание триггеров обработки данных для сервисов AWS, таких как Amazon Simple Storage Service. (Amazon S3) и Amazon DynamoDB.

  • Обработка потоковых данных, хранящихся в Amazon Kinesis.

  • Создайте собственный серверный ВМ, работающий с масштабом, производительностью и безопасностью AWS.

Lambda — это высокодоступная услуга. Дополнительную информацию см. В Соглашении об уровне обслуживания AWS Lambda.

Когда мне следует использовать Lambda?

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

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

Если вам нужно управлять собственными вычислительными ресурсами, у AWS есть другие вычислительные сервисы для удовлетворить ваши потребности. Для пример:

  • Amazon Elastic Compute Cloud (Amazon EC2) предлагает широкий спектр типов инстансов EC2. выбирать из.Это позволяет вам настроить операционные системы, настройки сети и безопасности, а также весь программный стек. Ты несут ответственность за предоставление ресурсов, мониторинг работоспособности и производительности парка машин, а также использование доступности Зоны неисправности толерантность.

  • AWS Elastic Beanstalk позволяет развертывать и масштабировать приложения в Amazon EC2.Вы сохраняете владение и полный контроль над базовыми инстансами EC2.

Лямбда-характеристики

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

Элементы управления параллелизмом и масштабированием

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

Функции, определенные как образы контейнеров

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

Подпись кода
Подписание кода

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

Лямбда-удлинители

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

Функциональные чертежи

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

Доступ к базе данных

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

Доступ к файловым системам

Вы можете настроить функцию для монтирования файла Amazon Elastic File System (Amazon EFS). систему в локальный каталог.С Amazon EFS ваш функциональный код может получать доступ и изменять общие Ресурсы безопасно и с высоким уровнем параллелизма.

Начало работы с Lambda

Для эффективной работы с Lambda вам потребуется опыт программирования и знания в следующих областях: домены:

  • ОС и команды Linux, а также такие понятия, как процессы, потоки и права доступа к файлам.

  • Концепции облака и концепции IP-сетей (для общедоступных и частных сетей).

  • Концепции распределенных вычислений, такие как HTML как IPC, очереди, обмен сообщениями, уведомления, а также параллелизм.

  • Знакомство с сервисами и концепциями безопасности: AWS Identity and Access Management (IAM) и принципы контроля доступа, а также AWS Key Management Service (AWS KMS) и инфраструктура открытых ключей.

  • Знакомство с ключевыми сервисами, взаимодействующими с Lambda: Amazon API Gateway, Amazon S3, Amazon Simple Queue Service (Amazon SQS) и DynamoDB.

  • Настройка инстансов EC2 в Linux.

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

AWS также предоставляет следующие ресурсы для изучения бессерверных приложений. и лямбда:

Lambda интегрируется с другими сервисами AWS для вызова функций на основе события, которые вы укажете.Например:

  • Используйте API Gateway для обеспечения безопасного и масштабируемого шлюза для веб-API которые направляют HTTP-запросы к лямбда-функциям.

  • Для служб, которые генерируют очередь или поток данных (например, DynamoDB и Kinesis), Lambda опрашивает очередь или поток данных из службы и вызывает ваша функция для обработки полученных данных.

  • Определите события Amazon S3, которые вызывают функцию Lambda для обработки объектов Amazon S3, например, при создании или удалении объекта.

  • Используйте функцию Lambda для обработки сообщений Amazon SQS или уведомлений Amazon Simple Notification Service (Amazon SNS).

  • Используйте AWS Step Functions для объединения функций Lambda в бессерверные рабочие процессы, называемые конечными автоматами.

Доступ к Lambda

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

  • Консоль управления AWS — предоставляет веб-интерфейс для доступа ваши функции.Для получения дополнительной информации см. Настройка функций в консоли.

  • Интерфейс командной строки AWS (AWS CLI) — Предоставляет команды для широкого набора AWS Services, включая Lambda, и поддерживается в Windows, macOS и Linux.Для большего Для получения дополнительной информации см. Использование AWS Lambda с интерфейсом командной строки AWS.

  • SDK AWS — Предоставляет API для конкретных языков и управляет многими из сведения о соединении, такие как вычисление подписи, обработка повторных попыток запроса и ошибка умение обращаться.Для большего информацию см. в AWS SDK.

  • AWS CloudFormation — позволяет создавать шаблоны, определяющие вашу Lambda. Приложения.Для получения дополнительной информации см. Приложения AWS Lambda. AWS CloudFormation также поддерживает AWS Cloud Development Kit (CDK).

  • Модель бессерверного приложения AWS (AWS SAM) — Предоставляет шаблоны и интерфейс командной строки для настройки и управлять бессерверными приложениями AWS.Для получения дополнительной информации см. AWS SAM.

Цены на Lambda

Дополнительная плата за создание лямбда-функций не взимается.Есть плата за запуск функции и для передача данных между Lambda и другими сервисами AWS. Некоторые дополнительные функции Lambda (например, с предоставленным параллелизмом) также взимается плата. Для дополнительной информации, см. Цены на AWS Lambda.

AWS Lambda — часто задаваемые вопросы

Вопрос: Что такое расширения AWS Lambda?

AWS Lambda Extensions позволяет интегрировать Lambda с вашими любимыми инструментами для мониторинга, наблюдения, безопасности и управления.Расширения позволяют вам и вашим предпочтительным поставщикам инструментов подключиться к жизненному циклу Lambda и глубже интегрироваться в среду выполнения Lambda.

Вопрос: Как работают лямбда-расширения?

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

Q: Для чего я могу использовать Lambda-расширения?

Вы можете использовать расширения для своих любимых инструментов для мониторинга, наблюдения, безопасности и управления от AWS, а также от следующих партнеров: AppDynamics, Coralogix, Datadog, Dynatrace, Epsagon, HashiCorp, Honeycomb, Imperva, Lumigo, Check Point CloudGuard, New Relic, Thundra, Splunk, Sentry, Site24x7, Sumo Logic, AWS AppConfig, Amazon CodeGuru Profiler, Amazon CloudWatch Lambda Insights, AWS Distro для OpenTelemetry.Чтобы узнать больше об этих расширениях, посетите запись в блоге о запуске.

Вопрос: Как мне настроить Lambda-расширения и управлять ими?

Вы можете развернуть расширения с помощью слоев для одной или нескольких функций Lambda с помощью консоли, интерфейса командной строки или инструментов «Инфраструктура как код», таких как CloudFormation, AWS Serverless Application Model и Terraform. Для начала ознакомьтесь с документацией.

Вопрос: С какими средами выполнения можно использовать расширения AWS Lambda?

Здесь вы можете просмотреть список сред выполнения, поддерживающих расширения.

Q: Учитываются ли расширения в лимите пакета развертывания?

Да, общий размер разархивированной функции и всех расширений не может превышать предельный размер разархивированного пакета развертывания в 250 МБ.

В: Влияет ли использование расширения на производительность?

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

Вы можете использовать метрику PostRuntimeExecutionDuration для измерения дополнительного времени, которое требуется расширению после выполнения функции, и вы можете использовать метрику MaxMemoryUsed для измерения увеличения используемой памяти.Чтобы понять влияние определенного расширения, вы также можете использовать показатель «Продолжительность». В настоящее время ответ выполнения функции возвращается после завершения выполнения функции и выполнения расширения. Чтобы узнать больше, посетите документацию для разработчиков Lambda.

Q: Как будет взиматься плата за использование Lambda-расширений?

Расширения используют ту же модель биллинга, что и лямбда-функции. При использовании лямбда-функций с расширениями вы платите за обслуживаемые запросы и общее время вычислений, используемое для запуска вашего кода и всех расширений, с шагом в 1 мс.С вас будет взиматься плата за время вычислений в соответствии с существующими ценами на продолжительность лямбда-выражения. Чтобы узнать больше, ознакомьтесь с ценами на AWS Lambda.

Жизненный цикл Lambda состоит из трех отдельных фаз: «init», когда AWS Lambda инициализирует функцию, зависимости и расширения; «Invoke», когда Lambda выполняет код функции и расширения в ответ на триггеры; и «выключение» после завершения выполнения функции, но код расширения все еще может выполняться, и это может длиться до двух секунд.Вы будете платить за время вычислений, использованное для запуска кода расширения на всех трех этапах жизненного цикла Lambda. Чтобы узнать больше о жизненном цикле Lambda, см. Документацию по Lambda Execution Environment.

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

Q: Могу ли я создавать свои собственные расширения Lambda?

Да, с помощью API расширений времени выполнения AWS Lambda.Посетите документацию, чтобы узнать больше.

Вопрос: Как работают расширения при включенном Provisioned Concurrency?

Provisioned Concurrency сохраняет функции инициализированными и готовыми к ответу в миллисекундах с двузначным числом. Если этот параметр включен, Provisioned Concurrency также инициализирует расширения и поддерживает их готовность к выполнению вместе с кодом функции.

Q: Какие разрешения есть у расширений?

Потому что расширения выполняются в той же среде, что и лямбда-функция.У них есть доступ к тем же ресурсам, что и у функции, и разрешения распределяются между функцией и расширением, поэтому они используют общие учетные данные, роль и переменные среды. Расширения имеют доступ только для чтения к коду функции и могут читать и писать в / tmp.

Вопрос: Что такое API журналов времени выполнения AWS Lambda?

API журналов времени выполнения AWS Lambda позволяет использовать расширения для отправки журналов из функций AWS Lambda непосредственно в место назначения по вашему выбору.Расширения используют этот API для подписки на те же журналы, которые передаются в Amazon CloudWatch Logs, а затем могут обрабатывать, фильтровать и отправлять их в любое предпочтительное место назначения.

Вопрос: Как работает API журналов выполнения?

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

API журналов выполнения позволяет авторам расширений подписываться на одни и те же потоки журналов непосредственно из среды выполнения Lambda. После получения запроса на подписку служба Lambda передает журналы в расширение через HTTP или TCP, а также отправляет их в CloudWatch.

Вопрос: Как начать использовать API журналов выполнения?

Вы можете развернуть расширения, которые используют API журналов времени выполнения, с помощью слоев, для одной или нескольких функций Lambda с помощью консоли, интерфейса командной строки или инструментов инфраструктуры как кода, таких как CloudFormation, AWS Serverless Application Model и Terraform.

Вы можете использовать расширения для своих любимых инструментов для мониторинга, наблюдения, безопасности и управления от AWS, а также от следующих партнеров: Coralogix, Datadog, Honeycomb, Lumigo, New Relic, Sumo Logic и Amazon CloudWatch. Чтобы узнать больше об этих расширениях, посетите запись в блоге о запуске.

Вопрос: Влияет ли на производительность использование API журналов выполнения?

Вы можете использовать API журналов выполнения только из расширений AWS Lambda.Расширения могут повлиять на производительность вашей функции, поскольку они совместно используют ресурсы, такие как ЦП, память и хранилище, с функцией, а также потому, что расширения инициализируются до кода функции. Например, если расширение выполняет операции с интенсивными вычислениями, вы можете увидеть увеличение продолжительности выполнения вашей функции, потому что расширение и код функции совместно используют одни и те же ресурсы ЦП. Кроме того, каждая подписка на API журналов времени выполнения может потреблять дополнительную память для хранения журналов сверх того, что потребляет содержащее ее расширение.

Вопрос: Как будет взиматься плата за использование API журналов выполнения?

Дополнительная плата за использование API журналов времени выполнения AWS Lambda не взимается. Расширения, использующие API журналов времени выполнения, используют ту же модель выставления счетов, что и другие расширения и функции Lambda. Чтобы узнать больше о ценах на расширения, см. Часто задаваемые вопросы.

Вопрос: Отключает ли использование Runtime Logs API отправку журналов в Amazon CloudWatch Logs?

Нет, по умолчанию платформа Lambda отправляет все журналы в CloudWatch Logs, а использование Runtime Logs API не отключает выход в CloudWatch Logs.

Использование AWS Lambda с другими сервисами

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

Каждая служба, которая интегрируется с Lambda, отправляет данные вашей функции в JSON в виде мероприятие. Структура документ события отличается для каждого типа события и содержит данные о ресурсе или запрос, вызвавший функция. Среды выполнения лямбда преобразуют событие в объект и передают его вашей функции.

В следующем примере показано тестовое событие от Application Load Balancer, которое представляет GET запрос на / lambda? query = 1234ABCD .

Пример события от балансировщика нагрузки приложения

  {
    "requestContext": {
        "elb": {
            "targetGroupArn": "arn: aws: elasticloadbalancing: us-east-2: 123456789012: targetgroup / lambda-279XGJDqGZ5rsrHC2Fjr / 49e9d65c45c6791a"
        }
    },
    "httpMethod": "ПОЛУЧИТЬ",
    "путь": "/ лямбда",
    "queryStringParameters": {
        "query": "1234ABCD"
    },
    "заголовки": {
        «принять»: «текст / HTML, приложение / xhtml + xml, приложение / xml; q = 0.9, image / webp, image / apng, * / *; q = 0,8 ",
        "accept-encoding": "gzip",
        "accept-language": "en-US, en; q = 0.9",
        "соединение": "поддерживать активность",
        "host": "lambda-alb-123578498.us-east-2.elb.amazonaws.com",
        "update-insecure-requests": "1",
        "user-agent": "Mozilla / 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit / 537.36 (KHTML, например Gecko) Chrome / 71.0.3578.98 Safari / 537.36",
        "x-amzn-trace-id": "Root = 1-5c536348-3d683b8b04734faae651f476",
        «x-forwarded-for»: «72.12.164.125 ",
        "x-forwarded-port": "80",
        "x-forwarded-proto": "http",
        "x-imforwards": "20"
    },
    "тело": "",
    "isBase64Encoded": ложь
}  

Среда выполнения Lambda преобразует документ события в объект и передает его вашему обработчик функции.Для скомпилированных языков Lambda предоставляет определения для типов событий в библиотеке. См. Следующие темы для получения дополнительной информации.

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

Службы, которые Lambda считывает события из

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

Дополнительные сведения об архитектурах служб Lambda см. Архитектура, управляемая событиями в Руководство по лямбда-оператору .

Службы, которые синхронно вызывают лямбда-функции

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

Службы, асинхронно вызывающие лямбда-функции

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

Услуги, которые другими способами интегрируются с Lambda

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

Как использовать лямбда-функции Python — настоящий Python

Python и другие языки, такие как Java, C # и даже C ++, имеют лямбда-функции, добавленные к их синтаксису, тогда как такие языки, как LISP или семейство языков ML, Haskell, OCaml и F # , используйте лямбды как основную концепцию.

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

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

Все примеры, включенные в это руководство, были протестированы с Python 3.7.

Лямбда-исчисление

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

История

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

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

Функциональные языки берут свое начало в математической логике и лямбда-исчислении, в то время как императивные языки программирования охватывают основанную на состоянии модель вычислений, изобретенную Аланом Тьюрингом.Две модели вычислений, лямбда-исчисление и машины Тьюринга, могут быть преобразованы друг в друга. Эта эквивалентность известна как гипотеза Черча-Тьюринга.

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

Напротив, машина Тьюринга привела к императивному программированию на таких языках, как Fortran, C или Python.

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

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

Python по своей сути не является функциональным языком, но он изначально принял некоторые функциональные концепции. В январе 1994 года к языку были добавлены map () , filter () , reduce () и лямбда-оператор .

Первый пример

Вот несколько примеров, чтобы дать вам аппетит к некоторому коду Python, функциональному стилю.

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

>>>
  >>> def identity (x):
... вернуть x
  

identity () принимает аргумент x и возвращает его при вызове.

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

В приведенном выше примере выражение состоит из:

  • Ключевое слово: лямбда
  • Связанная переменная: x
  • Кузов: x

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

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

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

Вы можете применить указанную выше функцию к аргументу, заключив функцию и ее аргумент в круглые скобки:

>>>
  >>> (лямбда x: x + 1) (2)
3
  

Редукция — это стратегия лямбда-исчисления для вычисления значения выражения.В текущем примере он состоит из замены связанной переменной x аргументом 2 :

  (лямбда x: x + 1) (2) = лямбда 2: 2 + 1
                     = 2 + 1
                     = 3
  

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

>>>
  >>> add_one = лямбда x: x + 1
>>> add_one (2)
3
  

Вышеупомянутая лямбда-функция эквивалентна записи:

  def add_one (x):
    вернуть x + 1
  

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

>>>
  >>> full_name = lambda first, last: f'Полное имя: {first.title ()} {last.title ()} '
>>> полное_имя ('гидо', 'ван россум')
'Полное имя: Гвидо Ван Россум'
  

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

Анонимные функции

Следующие термины могут использоваться взаимозаменяемо в зависимости от типа языка программирования и культуры:

  • Анонимные функции
  • Лямбда-функции
  • Лямбда-выражения
  • Лямбда-абстракции
  • Лямбда-форма
  • Функциональные литералы

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

В буквальном смысле анонимная функция — это функция без имени. В Python анонимная функция создается с ключевым словом lambda . Говоря более свободно, ему может быть присвоено или нет имя. Рассмотрим анонимную функцию с двумя аргументами, определенную с помощью лямбда-выражения , но не связанную с переменной. Лямбде не присвоено имя:

>>>
  >>> лямбда x, y: x + y
  

Вышеупомянутая функция определяет лямбда-выражение, которое принимает два аргумента и возвращает их сумму.

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

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

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

Примечание : В интерактивном интерпретаторе одиночное подчеркивание ( _ ) привязано к последнему вычисленному выражению.

В приведенном выше примере _ указывает на лямбда-функцию. Дополнительные сведения об использовании этого специального символа в Python см. В статье «Значение подчеркивания в Python».

Другой шаблон, используемый в других языках, таких как JavaScript, — это немедленное выполнение лямбда-функции Python. Это известно как выражение с немедленным вызовом функции (IIFE, произносится как «iffy»). Вот пример:

>>>
  >>> (лямбда x, y: x + y) (2, 3)
5
  

Приведенная выше лямбда-функция определяется и затем сразу вызывается с двумя аргументами ( 2 и 3 ). Он возвращает значение 5 , которое является суммой аргументов.

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

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

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

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

>>>
  >>> high_ord_func = лямбда x, func: x + func (x)
>>> high_ord_func (2, лямбда x: x * x)
6
>>> high_ord_func (2, лямбда x: x + 3)
7
  

Python предоставляет функции высшего порядка как встроенные функции или в стандартной библиотеке. Примеры включают map () , filter () , functools.reduce () , а также ключевые функции, такие как sort () , sorted () , min () и max () . Вы будете использовать лямбда-функции вместе с функциями высшего порядка Python в разделе «Соответствующее использование лямбда-выражений».

Python Лямбда и регулярные функции

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

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

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

Функции

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

Модуль dis предоставляет функции для анализа байт-кода Python, сгенерированного компилятором Python:

>>>
  >>> импорт
>>> add = лямбда x, y: x + y
>>> введите (добавить)
<класс 'функция'>
>>> dis.dis (добавить)
  1 0 LOAD_FAST 0 (x)
              2 LOAD_FAST 1 (г)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> добавить
<функция <лямбда> в 0x7f30c6ce9ea0>
  

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

Теперь посмотрим на обычный функциональный объект:

>>>
  >>> импорт
>>> def add (x, y): вернуть x + y
>>> введите (добавить)
<класс 'функция'>
>>> dis.dis (добавить)
  1 0 LOAD_FAST 0 (x)
              2 LOAD_FAST 1 (г)
              4 BINARY_ADD
              6 RETURN_VALUE
>>> добавить
<функция добавить в 0x7f30c6ce9f28>
  

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

Отслеживание

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

>>>
  >>> div_zero = лямбда x: x / 0
>>> div_zero (2)
Отслеживание (последний вызов последний):
    Файл "", строка 1, в 
    Файл "", строка 1, в 
ZeroDivisionError: деление на ноль
  

Отслеживание исключения, возникшего при выполнении лямбда-функции, идентифицирует только функцию, вызвавшую исключение, как <лямбда> .

Вот такое же исключение, вызываемое нормальной функцией:

>>>
  >>> def div_zero (x): вернуть x / 0
>>> div_zero (2)
Отслеживание (последний вызов последний):
    Файл "", строка 1, в 
    Файл "", строка 1, в div_zero
ZeroDivisionError: деление на ноль
  

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

Синтаксис

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

  • Он может содержать только выражения и не может включать в себя операторы.
  • Записывается как одна строка исполнения.
  • Он не поддерживает аннотации типов.
  • Может быть вызван немедленно (IIFE).

Нет выписок

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

Этот надуманный пример предназначен для утверждения , что параметр x имеет значение 2 . Но интерпретатор идентифицирует SyntaxError при синтаксическом анализе кода, который включает в себя оператор assert в теле лямбда-выражения .

Одно выражение

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

>>>
  >>> (лямбда x:
... (x% 2 и «нечетное» или «четное»)) (3)
'странный'
  

В приведенном выше примере возвращается строка «нечетный», , если лямбда-аргумент нечетный, и «четный», , если аргумент четный. Он занимает две строки, потому что заключен в круглые скобки, но остается одним выражением.

Обозначения типа

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

  def full_name (first: str, last: str) -> str:
    return f '{first.title ()} {last.title ()}'
  

Ошибка любого типа с full_name () может быть обнаружена такими инструментами, как mypy или pyre , тогда как SyntaxError с эквивалентной лямбда-функцией возникает во время выполнения:

>>>
  >>> lambda first: str, last: str: first.title () + "" + last.title () -> str
  Файл "", строка 1
    лямбда сначала: str, last: str: first.title () + "" + last.title () -> str

SyntaxError: недопустимый синтаксис
  

Подобно попытке включить оператор в лямбда-выражение, добавление аннотации типа немедленно приводит к ошибке SyntaxError во время выполнения.

IIFE

Вы уже видели несколько примеров выполнения немедленно вызываемой функции:

>>>
  >>> (лямбда x: x * x) (3)
9
  

Вне интерпретатора Python эта функция, вероятно, не используется на практике.Это прямое следствие того, что лямбда-функция вызывается в том виде, в котором она определена. Например, это позволяет передать определение лямбда-выражения Python функции более высокого порядка, такой как map () , filter () или functools.reduce () , или ключевой функции.

Аргументы

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

  • Позиционные аргументы
  • Именованные аргументы (иногда называемые аргументами ключевого слова)
  • Переменный список аргументов (часто обозначается как varargs )
  • Переменный список аргументов ключевого слова
  • Аргументы только для ключевых слов

Следующие примеры иллюстрируют варианты, доступные вам для передачи аргументов лямбда-выражениям:

>>>
  >>> (лямбда x, y, z: x + y + z) (1, 2, 3)
6
>>> (лямбда x, y, z = 3: x + y + z) (1, 2)
6
>>> (лямбда x, y, z = 3: x + y + z) (1, y = 2)
6
>>> (лямбда * аргументы: сумма (аргументы)) (1,2,3)
6
>>> (лямбда ** kwargs: sum (kwargs.values ​​())) (один = 1, два = 2, три = 3)
6
>>> (лямбда x, *, y = 0, z = 0: x + y + z) (1, y = 2, z = 3)
6
  

Декораторы

В Python декоратор — это реализация шаблона, который позволяет добавлять поведение к функции или классу. Обычно это выражается с помощью синтаксиса @decorator перед функцией. Вот надуманный пример:

  def some_decorator (f):
    def обертывания (* args):
        print (f "Вызов функции '{f .__ name__}'")
        вернуть f (аргументы)
    возвратные обертки

@some_decorator
def Decorated_function (x):
    print (f "С аргументом '{x}'")
  

В приведенном выше примере some_decorator () — это функция, которая добавляет поведение к Decorated_function () , так что вызов Decorated_function ("Python") приводит к следующему результату:

  Вызов функции «Decorated_function»
С аргументом Python
  

Decorated_function () печатает только с аргументом «Python» , но декоратор добавляет дополнительное поведение, которое также печатает Вызов функции «Decorated_function» .

К лямбде можно применить декоратор. Хотя украсить лямбда-выражение синтаксисом @decorator невозможно, декоратор — это просто функция, поэтому он может вызывать лямбда-функцию:

  1 # Определение декоратора
 2def trace (f):
 3 def wrap (* args, ** kwargs):
 4 print (f "[TRACE] func: {f .__ name__}, args: {args}, kwargs: {kwargs}")
 5 вернуть f (* args, ** kwargs)
 6
 7 возвратная пленка
 8
 9 # Применение декоратора к функции
10 @ след
11def add_two (x):
12 возврат x + 2
13
14 # Вызов декорированной функции
15add_two (3)
16
17 # Применение декоратора к лямбде
18print ((след (лямбда x: x ** 2)) (3))
  

add_two () , украшенный @trace в строке 11, вызывается с аргументом 3 в строке 15.Напротив, в строке 18 сразу же задействуется лямбда-функция, которая встраивается в вызов trace () , декоратора. Когда вы выполните приведенный выше код, вы получите следующее:

  [TRACE] func: add_two, args: (3,), kwargs: {}
[TRACE] func: <лямбда>, аргументы: (3,), kwargs: {}
9
  

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

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

  список (карта (трассировка (лямбда x: x * 2), диапазон (3)))
  

Первый аргумент map () — это лямбда, умножающая свой аргумент на 2 . Эта лямбда украшена следом () . При выполнении приведенный выше пример выводит следующее:

  [TRACE] Вызов  с аргументами (0,) и kwargs {}
[TRACE] Вызов  с аргументами (1,) и kwargs {}
[TRACE] Вызов  с аргументами (2,) и kwargs {}
[0, 2, 4]
  

Результат [0, 2, 4] — это список, полученный умножением каждого элемента диапазона (3) .А пока рассмотрим диапазон (3) , эквивалентный списку [0, 1, 2] .

Вы увидите карту () более подробно на карте.

Лямбда также может быть декоратором, но это не рекомендуется. Если вам нужно это сделать, обратитесь к PEP 8, Рекомендации по программированию.

Чтобы узнать больше о декораторах Python, ознакомьтесь с Primer on Python Decorators.

Закрытие

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

Понятия лямбда-выражений и замыканий не обязательно связаны, хотя лямбда-функции могут быть замыканиями точно так же, как обычные функции могут быть замыканиями. В некоторых языках есть специальные конструкции для замыкания или лямбда (например, Groovy с анонимным блоком кода в качестве объекта Closure) или лямбда-выражения (например, лямбда-выражение Java с ограниченным параметром закрытия).

Вот замыкание, построенное с помощью обычной функции Python:

  1def outer_func (x):
 2 года = 4
 3 def inner_func (z):
 4 print (f "x = {x}, y = {y}, z = {z}")
 5 вернуть x + y + z
 6 возвратите inner_func
 7
 8 для i в диапазоне (3):
 9 закрытие = external_func (я)
10 print (f "закрытие ({i + 5}) = {закрытие (i + 5)}")
  

outer_func () возвращает inner_func () , вложенную функцию, которая вычисляет сумму трех аргументов:

  • x передается в качестве аргумента функции outer_func () .
  • y — переменная, локальная для outer_func () .
  • z — аргумент, переданный в inner_func () .

Для проверки поведения функций outer_func () и inner_func () , outer_func () вызывается три раза в цикле for , который выводит следующее:

  х = 0, у = 4, г = 5
закрытие (5) = 9
х = 1, у = 4, г = 6
закрытие (6) = 11
х = 2, у = 4, г = 7
закрытие (7) = 13
  

В строке 9 кода inner_func () , возвращенный вызовом outer_func () , привязан к замыканию имени .В строке 5 inner_func () захватывает x и y , потому что у него есть доступ к своей среде внедрения, так что при вызове закрытия он может работать с двумя свободными переменными x и y. .

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

  1def outer_func (x):
 2 года = 4
 3 вернуть лямбда z: x + y + z
 4
 5 для i в диапазоне (3):
 6 закрытие = external_func (i)
 7 print (f "закрытие ({i + 5}) = {закрытие (i + 5)}")
  

Когда вы выполните приведенный выше код, вы получите следующий результат:

 закрытие  (5) = 9
закрытие (6) = 11
закрытие (7) = 13
  

В строке 6 outer_func () возвращает лямбду и присваивает ее закрытию переменной .В строке 3 тело лямбда-функции ссылается на x и y . Переменная y доступна во время определения, тогда как x определяется во время выполнения, когда вызывается outer_func () .

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

Время оценки

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

Сначала проверьте сценарий, используя обычную функцию:

>>>
  1 >>> def wrap (n):
 2 ... def f ():
 3 ... печать (n)
 4 ... вернуть f
 5 ...
 6 >>> числа = 'один', 'два', 'три'
 7 >>> funcs = []
 8 >>> для n цифрами:
 9 ... функц.добавить (обернуть (n))
10 ...
11 >>> для f в функциях:
12 ... f ()
13 ...
14one
15два
16три
  

В нормальной функции n оценивается во время определения в строке 9, когда функция добавляется в список: funcs.append (wrap (n)) .

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

>>>
  1 >>> числа = 'один', 'два', 'три'
 2 >>> funcs = []
 3 >>> для n цифрами:
 4... funcs.append (лямбда: print (n))
 5 ...
 6 >>> для f в функциях:
 7 ... f ()
 8 ...
 9три
10три
11три
  

Неожиданный результат возникает из-за того, что свободная переменная n , как реализовано, связана во время выполнения лямбда-выражения. Лямбда-функция Python в строке 4 — это замыкание, которое захватывает n , свободную переменную, привязанную во время выполнения. Во время выполнения при вызове функции f в строке 7 значение n составляет три .

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

>>>
  1 >>> числа = 'один', 'два', 'три'
 2 >>> funcs = []
 3 >>> для n цифрами:
 4 ... funcs.append (лямбда n = n: print (n))
 5 ...
 6 >>> для f в функциях:
 7 ... f ()
 8 ...
 9one
10два
11три
  

Лямбда-функция Python ведет себя как обычная функция в отношении аргументов. Следовательно, лямбда-параметр может быть инициализирован значением по умолчанию: параметр n принимает внешний n как значение по умолчанию.Лямбда-функцию Python можно было бы записать как lambda x = n: print (x) и получить тот же результат.

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

Тестирование лямбда-выражений

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

unittest

Модуль unittest обрабатывает лямбда-функции Python аналогично обычным функциям:

  импорт unittest

addtwo = лямбда x: x + 2

класс LambdaTest (unittest.Прецедент):
    def test_add_two (сам):
        self.assertEqual (addtwo (2), 4)

    def test_add_two_point_two (сам):
        self.assertEqual (addtwo (2.2), 4.2)

    def test_add_three (сам):
        # Должен потерпеть неудачу
        self.assertEqual (addtwo (3), 6)

если __name__ == '__main__':
    unittest.main (многословие = 2)
  

LambdaTest определяет тестовый пример с тремя методами тестирования, каждый из которых выполняет тестовый сценарий для addtwo () , реализованный как лямбда-функция.Выполнение файла Python lambda_unittest.py , который содержит LambdaTest , дает следующее:

  $ python lambda_unittest.py
test_add_three (__main __. LambdaTest) ... FAIL
test_add_two (__main __. LambdaTest) ... хорошо
test_add_two_point_two (__main __. LambdaTest) ... хорошо

================================================== ====================
ОТКАЗ: test_add_three (__main __. LambdaTest)
-------------------------------------------------- --------------------
Отслеживание (последний вызов последний):
  Файл "lambda_unittest.py ", строка 18, в test_add_three
    self.assertEqual (addtwo (3), 6)
AssertionError: 5! = 6

-------------------------------------------------- --------------------
Выполнить 3 теста за 0,001 с

ВЫПОЛНЕНО (отказов = 1)
  

Как и ожидалось, у нас есть два успешных тестовых примера и один сбой для test_add_three : результат 5 , но ожидаемый результат был 6 . Этот сбой вызван преднамеренной ошибкой в ​​тестовом примере. Изменение ожидаемого результата с 6 на 5 удовлетворит все тесты для LambdaTest .

доктест

Модуль doctest извлекает интерактивный код Python из строки docstring для выполнения тестов. Хотя синтаксис лямбда-функций Python не поддерживает типичную строку документации , можно присвоить строку элементу __doc__ именованной лямбда:

  addtwo = лямбда x: x + 2
addtwo .__ doc__ = "" "Добавьте 2 к числу.
    >>> addtwo (2)
    4
    >>> addtwo (2.2)
    4.2
    >>> addtwo (3) # Должен потерпеть неудачу
    6
    "" "

если __name__ == '__main__':
    импорт документов
    doctest.testmod (verbose = True)
  

doctest в комментарии документа лямбда addtwo () описывает те же тестовые случаи, что и в предыдущем разделе.

Когда вы выполняете тесты через doctest.testmod () , вы получаете следующее:

  $ python lambda_doctest.py
Пытающийся:
    addtwo (2)
Ожидая:
    4
ОК
Пытающийся:
    addtwo (2.2)
Ожидая:
    4.2
ОК
Пытающийся:
    addtwo (3) # Должен потерпеть неудачу
Ожидая:
    6
************************************************* ********************
Файл "lambda_doctest.py", строка 16, в __main __. Addtwo
Неудачный пример:
    addtwo (3) # Должен потерпеть неудачу
Ожидал:
    6
Получил:
    5
1 предмет не прошел тестов:
    __основной__
************************************************* ********************
По 1 предмету были сбои:
   1 из 3 в __main __. Addtwo
3 теста по 2 задания.
2 пройдены и 1 не пройден.
*** Тест не пройден *** 1 сбой. 

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

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

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

Злоупотребления лямбда-выражением

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

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

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

  • Он не соответствует руководству по стилю Python (PEP 8)
  • Это громоздкий и трудный для чтения.
  • Это излишне умно за счет трудной читаемости.

Вызов исключения

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

>>>
  >>> def throw (ex): поднять ex
>>> (лямбда: throw (Exception ('Произошло что-то плохое'))) ()
Отслеживание (последний вызов последний):
    Файл "", строка 1, в 
    Файл "", строка 1, в 
    Файл "", строка 1, в throw
Исключение: произошло что-то плохое.
  

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

Загадочный стиль

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

Следующий пример лямбда-выражения содержит несколько вариантов неправильного стиля:

>>>
  >>> (lambda _: list (map (lambda _: _ // 2, _))) ([1,2,3,4,5,6,7,8,9,10] )
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
  

Знак подчеркивания ( _ ) указывает на переменную, на которую не нужно ссылаться явно.Но в этом примере три _ относятся к разным переменным. Первоначальное обновление этого лямбда-кода могло состоять в том, чтобы назвать переменные:

>>>
  >>> (lambda some_list: list (map (lambda n: n // 2,
                                some_list))) ([1,2,3,4,5,6,7,8,9,10])
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
  

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

>>>
  >>> def div_items (some_list):
      div_by_two = лямбда n: n // 2
      вернуть карту (div_by_two, some_list)
>>> список (div_items ([1,2,3,4,5,6,7,8,9,10])))
[0, 1, 1, 2, 2, 3, 3, 4, 4, 5]
  

Это все еще не оптимально, но показывает вам возможный способ сделать код и, в частности, лямбда-функции Python более удобочитаемыми.В разделе «Альтернативы лямбдам» вы научитесь заменять map () и лямбда на составные части списков или выражения-генераторы. Это резко улучшит читаемость кода.

Классы Python

Вы можете, но не должны писать методы класса как лямбда-функции Python. Следующий пример представляет собой совершенно законный код Python, но демонстрирует нетрадиционный код Python, основанный на лямбде . Например, вместо того, чтобы реализовать __str__ как обычную функцию, он использует лямбда .Точно так же brand и year являются свойствами, также реализованными с помощью лямбда-функций вместо обычных функций или декораторов:

  класс Автомобиль:
    "" "Автомобиль с методами как лямбда-функциями." ""
    def __init __ (я, бренд, год):
        self.brand = бренд
        self.year = год

    brand = property (лямбда self: getattr (self, '_brand'),
                     лямбда self, значение: setattr (self, '_brand', value))

    год = свойство (лямбда-я: getattr (self, '_year'),
                    лямбда self, значение: setattr (self, '_year', value))

    __str__ = лямбда self: f '{self.brand} {self.year} '# 1: ошибка E731

    honk = lambda self: print ('Honk!') # 2: ошибка E731
  

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

  E731 не назначают лямбда-выражение, используйте def
  

Хотя flake8 не указывает на проблему с использованием лямбда-функций Python в свойствах, их трудно читать и они подвержены ошибкам из-за использования нескольких строк, таких как '_brand' и '_year '.

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

  def __str __ (self):
    return f '{self.brand} {self.year}'
  

марка запишется следующим образом:

  @property
def brand (self):
    вернуть self._brand

@ brand.setter
def brand (self, value):
    self._brand = значение
  

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

Надлежащее использование лямбда-выражений

Лямбды в Python, как правило, являются предметом споров. Вот некоторые из аргументов против лямбд в Python:

  • Проблемы с читаемостью
  • Навязывание функционального мышления
  • Тяжелый синтаксис с ключевым словом лямбда

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

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

Классические функциональные конструкции

Лямбда-функции регулярно используются со встроенными функциями map () и filter () , а также functools.reduce () , представленными в модуле functools . Следующие три примера являются соответствующими иллюстрациями использования этих функций с лямбда-выражениями в качестве сопутствующих:

>>>
  >>> список (map (lambda x: x.upper (), ['кошка', 'собака', 'корова']))
["КОШКА", "СОБАКА", "КОРОВА"]
>>> list (filter (lambda x: 'o' in x, ['cat', 'dog', 'cow']))
['собака', 'корова']
>>> из импорта functools уменьшить
>>> reduce (lambda acc, x: f '{acc} | {x}', ['кошка', 'собака', 'корова'])
'кошка | собака | корова'
  

Возможно, вам придется прочитать код, похожий на приведенные выше примеры, хотя и с более релевантными данными. По этой причине важно распознавать эти конструкции. Тем не менее, у этих конструкций есть эквивалентные альтернативы, которые считаются более питоническими.В разделе «Альтернативы лямбдам» вы узнаете, как преобразовывать функции высшего порядка и соответствующие лямбды в другие, более идиоматические формы.

Ключевые функции

Ключевые функции в Python — это функции высшего порядка, которые принимают параметр ключ в качестве именованного аргумента. Ключ получает функцию, которая может быть лямбда . Эта функция напрямую влияет на алгоритм, управляемый самой ключевой функцией. Вот некоторые ключевые функции:

  • sort () : метод списка
  • отсортировано () , мин. () , макс. () : встроенных функций
  • nlargest () и nsmallest () : в модуле алгоритма очереди кучи heapq

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

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

>>>
  >>> ids = ['id1', 'id2', 'id30', 'id3', 'id22', 'id100']
>>> print (sorted (ids)) # Лексикографическая сортировка
['id1', 'id100', 'id2', 'id22', 'id3', 'id30']
>>> sorted_ids = sorted (ids, key = lambda x: int (x [2:])) # Целочисленная сортировка
>>> печать (sorted_ids)
['id1', 'id2', 'id3', 'id22', 'id30', 'id100']
  

Фреймворки пользовательского интерфейса

UI-фреймворки, такие как Tkinter, wxPython или.NET Windows Forms с IronPython используют лямбда-функции для сопоставления действий в ответ на события пользовательского интерфейса.

Наивная программа Tkinter ниже демонстрирует использование лямбды , назначенной команде кнопки Reverse :

  импорт tkinter as tk
import sys

окно = tk.Tk ()
window.grid_columnconfigure (0, вес = 1)
window.title ("Лямбда")
window.geometry ("300x100")
label = tk.Label (window, text = "Лямбда-исчисление")
label.grid (столбец = 0, строка = 0)
кнопка = тк.Кнопка(
    окно,
    text = "Обратный",
    command = lambda: label.configure (text = label.cget ("текст") [:: - 1]),
)
button.grid (столбец = 0, строка = 1)
window.mainloop ()
  

При нажатии кнопки Reverse запускается событие, которое запускает лямбда-функцию, меняя метку с Lambda Calculus на suluclaC adbmaL *:

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

Чтобы изучить wxPython, прочтите статью Как создать приложение Python с графическим интерфейсом пользователя с помощью wxPython.

Интерпретатор Python

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

таймит

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

>>>
  >>> из timeit import timeit
>>> timeit ("factorial (999)", "from math import factorial", number = 10)
0.0013087529951008037
  

Когда оператор передается в виде строки, timeit () нужен полный контекст. В приведенном выше примере это обеспечивается вторым аргументом, который устанавливает среду, необходимую для функции main, для синхронизации. В противном случае возникнет исключение NameError .

Другой подход — использовать лямбда :

>>>
  >>> из математического импорта факториала
>>> timeit (лямбда: факториал (999), число = 10)
0.0012704220062005334
  

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

Обезьяна Patching

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

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

  из contextlib import contextmanager
секреты импорта

def gen_token ():
    "" "Создать случайный токен." ""
    return f'TOKEN_ {secrets.token_hex (8)} '

@contextmanager
def mock_token ():
    "" "Менеджер контекста для обезьяньего исправления секретов.token_hex
    функция во время тестирования.
    "" "
    default_token_hex = секреты.token_hex
    secretts.token_hex = lambda _: 'feedfacecafebeef'
    урожай
    secretts.token_hex = default_token_hex

def test_gen_key ():
    "" "Проверить случайный токен." ""
    с mock_token ():
        assert gen_token () == f "ТОКЕН _ {'feedfacecafebeef'}"

test_gen_key ()
  

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

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

Фреймворки модульного тестирования

, такие как unittest и pytest , выводят эту концепцию на более высокий уровень сложности.

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

  секреты импорта

def gen_token ():
    return f'TOKEN_ {secrets.token_hex (8)} '

def test_gen_key (патч обезьяны):
    monkeypatch.setattr ('secrets.token_hex', lambda _: 'feedfacecafebeef')
    assert gen_token () == f "ТОКЕН _ {'feedfacecafebeef'}"
  

С помощью приспособления pytest monkeypatch , секретов.token_hex () перезаписывается лямбда-выражением, которое возвращает детерминированное значение, feedfacecafebeef , что позволяет проверить тест. Инструмент pytest monkeypatch позволяет вам контролировать объем переопределения. В приведенном выше примере вызов secrets.token_hex () в последующих тестах без использования исправлений обезьяны приведет к нормальной реализации этой функции.

Выполнение теста pytest дает следующий результат:

  $ pytest test_token.py -v
============================= Начинается тестовая сессия ================== ============
платформа Linux - Python 3.7.2, pytest-4.3.0, py-1.8.0, pluggy-0.9.0
cachedir: .pytest_cache
корневой каталог: / home / andre / AB / tools / bpython, inifile:
собрано 1 предмет

test_token.py::test_gen_key ПРОЙДЕН [100%]

=========================== 1 пройдено за 0,01 секунды ================== =========
  

Тест проходит, так как мы подтвердили, что gen_token () был задействован, и результаты были ожидаемыми в контексте теста.

Альтернативы лямбдам

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

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

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

Карта

Встроенная функция map () принимает функцию в качестве первого аргумента и применяет ее к каждому из элементов своего второго аргумента, итерации . Примерами итераций являются строки, списки и кортежи. Для получения дополнительной информации об итерациях и итераторах ознакомьтесь с Iterables и Iterators.

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

>>>
  >>> list (map (lambda x: x.capitalize (), ['cat', 'dog', 'cow']))
["Кошка", "Собака", "Корова"]
  

Вам необходимо вызвать list () , чтобы преобразовать итератор, возвращаемый map () , в расширенный список, который может отображаться в интерпретаторе оболочки Python.

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

>>>
  >>> [x.capitalize () вместо x в ['кошка', 'собака', 'корова']]
["Кошка", "Собака", "Корова"]
  

Фильтр

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

>>>
  >>> даже = лямбда x: x% 2 == 0
>>> список (фильтр (даже, диапазон (11)))
[0, 2, 4, 6, 8, 10]
  

Обратите внимание, что filter () возвращает итератор, следовательно, необходимо вызывать встроенный тип list , который создает список с учетом итератора.

Реализация, использующая конструкцию понимания списка, дает следующее:

>>>
  >>> [x для x в диапазоне (11), если x% 2 == 0]
[0, 2, 4, 6, 8, 10]
  

Уменьшить

Начиная с Python 3, reduce () превратилась из встроенной функции в функцию модуля functools . Как и map () и filter () , его первые два аргумента являются соответственно функцией и итерацией. Он также может принимать инициализатор в качестве третьего аргумента, который используется в качестве начального значения результирующего аккумулятора.Для каждого элемента итерируемого объекта reduce () применяет функцию и накапливает результат, который возвращается, когда итерируемый объект исчерпан.

Чтобы применить reduce () к списку пар и вычислить сумму первого элемента каждой пары, вы можете написать это:

>>>
  >>> import functools
>>> пары = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> functools.reduce (лямбда-совпадение, пара: совпадение + пара [0], пары, 0)
6
  

Более идиоматический подход с использованием выражения генератора в качестве аргумента функции sum () в примере выглядит следующим образом:

>>>
  >>> пары = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> sum (x [0] для x попарно)
6
  

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

>>>
  >>> пары = [(1, 'a'), (2, 'b'), (3, 'c')]
>>> сумма (x вместо x, _ попарно)
6
  

Использование подчеркивания ( _ ) — это соглашение Python, указывающее, что вы можете игнорировать второе значение пары.

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

Лямбды питонические или нет?

PEP 8, руководство по стилю кода Python, гласит:

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

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

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

Помимо узких рамок Python lambda , Как написать красивый код Python с помощью PEP 8 — отличный ресурс, который вы можете захотеть проверить относительно стиля кода в Python.

Заключение

Теперь вы знаете, как использовать функции лямбда-выражения Python и можете:

  • Напишите лямбды Python и используйте анонимные функции
  • Выбирайте с умом между лямбдами или обычными функциями Python
  • Избегайте чрезмерного использования лямбд
  • Использование лямбда-выражений с функциями высшего порядка или ключевыми функциями Python

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

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