Лямбда функции анонимные функции
В этой статье вы узнаете о том, что такое лямбда-функции в Python. На самом деле, если вы знаете, что такое функции и умеете с ними работать, то знаете и что такое лямбда.
Лямбда-функция в Python — это просто функция Python. Но это некий особенный тип с ограниченными возможностями. Если есть желание погрузиться глубже и узнать больше, то эта статья целиком посвящена lambda .
Что такое лямбда в Python?
Прежде чем переходить как разбору понятия лямбда в Python, попробуем понять, чем является обычная функция Python на более глубоком уровне.
Для этого потребуется немного поменять направление мышление. Как вы знаете, все в Python является объектом.
Например, когда мы запускаем эту простейшую строку кода
Создается объект Python типа int , который сохраняет значение 5. x же является символом, который ссылается на объект.
Теперь проверим тип x и адрес, на которой он ссылается. Это можно сделать с помощью встроенных функций type и id .
В итоге x ссылается на объект типа int , а расположен он по адресу, который вернула функция id .
Просто и понятно.
А что происходит при определении вот такой функции:
Повторим упражнение и узнаем type и id объекта f .
Оказывается, в Python есть класс function , а только что определенная функция f — это его экземпляр. Так же как x был экземпляром класса integer . Другими словами, о функциях можно думать как о переменных. Разница лишь в том, что переменные хранят данные, а функции — код.
Это же значит, что функции можно передать в качестве аргументов другим функциям или даже использовать их как тип возвращаемого значения.
Рассмотрим простой пример, где функция f передается другой функции.
Попробуйте разобраться самостоятельно с тем, что делает этот код, прежде чем читать дальше.
Итак, modify_list — это функция, которая принимает список L и функцию fn в качестве аргументов. Затем она перебирает список элемент за элементом и применяет функцию к каждому из них.
Это общий способ изменения объектов списка, ведь он позволяет передать функцию, которая займется преобразованием. Так, если передать modify_list функцию f , то результатом станет список, где все значения будут возведены в квадрат.
Но можно передать и любую другую, которая изменит оригинальный список другим способом. Это очень мощный инструмент.
Теперь, когда с основами разобрались, стоит перейти к лямбда. Лямбда в Python — это просто еще один способ определения функции. Вот базовый синтаксис лямбда-функции в Python:
Лямбда принимает любое количество аргументов (или ни одного), но состоит из одного выражения. Возвращаемое значение — значение, которому присвоена функция. Например, если нужно определить функцию f из примера выше, то это можно сделать вот так:
Но возникает вопрос: а зачем нужны лямбда-функции, если их можно объявлять традиционным образом? Но на самом деле, они полезны лишь в том случае, когда нужна одноразовая функция. Такие функции еще называют анонимными. И, как вы увидите дальше, есть масса ситуаций, где они оказываются нужны.
Лямбда с несколькими аргументами
Определить лямбда-функцию с одним аргументом не составляет труда.
А если их должно быть несколько, то достаточно лишь разделить значения запятыми. Предположим, что нужна функция, которая берет два числовых аргумента и возвращает их произведение.
Отлично! А как насчет лямбда-функции без аргументов?
Лямбда-функция без аргументов
Допустим, нужно создать функцию без аргументов, которая бы возвращала True . Этого можно добиться с помощью следующего кода.
Несколько лямбда-функций
В определенный момент возникнет вопрос: а можно ли иметь лямбда-функцию из нескольких строк.
Ответ однозначен: нет.
Лямбда-функции в Python всегда принимают только одно выражение. Если же их несколько, то лучше создать обычную функцию.
Примеры лямбда-функций
Теперь рассмотрим самые распространенные примеры использования лямбда-функций.
Лямбда-функция и map
Распространенная операция со списками в Python — применение операции к каждому элементу.
map() — это встроенная функция Python, принимающая в качестве аргумента функцию и последовательность. Она работает так, что применяет переданную функцию к каждому элементу.
Предположим, есть список целых чисел, которые нужно возвести в квадрат с помощью map .
Обратите внимание на то, что в Python3 функция map возвращает объект Map , а в Python2 — список.
Так, вместо определения функции и передачи ее в map в качестве аргумента, можно просто использовать лямбда для быстрого определения ее прямо внутри. В этом есть смысл, если упомянутая функция больше не будет использоваться в коде.
Вот еще один пример.
Лямбда-функция и filter
filter() — это еще одна встроенная функция, которая фильтрует последовательность итерируемого объекта.
Другими словами, функция filter отфильтровывает некоторые элементы итерируемого объекта (например, списка) на основе какого-то критерия. Критерий определяется за счет передачи функции в качестве аргумента. Она же применяется к каждому элементу объекта.
Если возвращаемое значение — True , элемент остается. В противном случае — отклоняется. Определим, например, простую функцию, которая возвращает True для четных чисел и False — для нечетных:
С лямбда-функциями это все можно сделать максимально сжато. Код выше можно преобразовать в такой, написанный в одну строку.
И в этом сила лямбда-функций.
Лямбда-функция и сортировка списков
Сортировка списка — базовая операция в Python. Если речь идет о списке чисел или строк, то процесс максимально простой. Подойдут встроенные функции sort и sorted .
Но иногда имеется список кастомных объектов, сортировать которые нужно на основе значений одного из полей. В таком случае можно передать параметр key в sort или sorted . Он и будет являться функцией.
Функция применяется ко всем элементам объекта, а возвращаемое значение — то, на основе чего выполнится сортировка. Рассмотрим пример. Есть класс Employee .
Теперь создадим экземпляры этого класса и добавим их в список.
Предположим, что мы хотим отсортировать его на основе поля age сотрудников. Вот что нужно сделать для этого:
Лямбда-выражение было использовано в качестве параметра key вместо отдельного ее определения и затем передачи в функцию sort .
Пара слов о выражениях и инструкциях
Как уже упоминалось, лямбда могут иметь только одно выражение (expression) в теле.
Обратите внимание, что речь идет не об инструкции (statement).
Выражение и инструкции — две разные вещи, в которых часто путаются. В программировании инструкцией является строка кода, выполняющая что-то, но не генерирующая значение.
Например, инструкция if или циклы for и while являются примерами инструкций. Заменить инструкцию на значение попросту невозможно.
А вот выражения — это значения. Запросто можно заменить все выражения в программе на значения, и программа продолжит работать корректно.
- 3 + 5 — выражение со значением 8
- 10 > 5 — выражение со значением True
- True and (5 < 3) — выражение со значением False
Тело лямбда-функции должно являться выражением, поскольку его значение будет тем, что она вернет. Обязательно запомните это для работы с лямбда-функциями в будущем.
Как вы уже знаете, ключевое слово def используется для определения стандартных функций в Python. Но, кроме таких обычных функций, в Python существуют так называемые анонимные или лямбда-функции. Для их создания используется ключевое слово lambda. Обычно такая функция не предназначена для повторного применения.
Лямбда-функция может иметь ноль или более аргументов перед символом ‘:’. При вызове такой функции выполняется выражение, указанное после ‘:’.
Пример определения лямбда-функции:
Приведенная выше лямбда-функция начинается с ключевого слова lambda, за которым следует параметр x. Выражение x ** 3 после ‘:’ возвращает вызывающему коду значение куба переданного числа. Сама лямбда-функция lambda x : x ** 3 присваивается переменной get_cube для ее последующего вызова как именованной функции. Имя переменной становится именем функции, чтобы мы могли работать с ней как с обычной функцией.
Пример вызова лямбда-функции:
Приведенное выше определение лямбда-функции аналогично следующей стандартной функции:
Выражение не обязательно должно всегда возвращать значение. Следующая лямбда-функция не возвращает ничего.
Пример лямбда-функции, не возвращающей значение:
Лямбда-функция может иметь только одно выражение. Очевидно, что она не может заменить функцию, тело которой содержит условия, циклы и т.д.
Следующая лямбда-функция содержит несколько параметров.
Пример лямбда-функции с тремя параметрами:
Также лямбда-функция может принимать любое количество параметров.
Пример лямбда-функции с неопределенным числом аргументов (используются только первые 3):
Лямбда-функция без параметров
Ниже приведен пример лямбда-функции без параметров.
Анонимная функция
Мы можем объявить лямбда-функцию и вызвать ее как анонимную функцию, не присваивая ее переменной.
Пример анонимной лямбда-функции:
Здесь lambda x: x3 определяет анонимную функцию и вызывает ее один раз, передавая аргументы в скобках (lambda x: x3)(10).
В Python функции, как и литералы, можно передавать в качестве аргументов.
Пример передачи лямбда-функции в качестве параметра:
Представленная выше функция run_task() определена с параметром task, который вызывается как функция внутри run_task(). run_task(lambda : print(‘Task is complete!’)) вызывает функцию run_task() с анонимной лямбда-функцией в качестве аргумента.
В Python есть встроенные функции, которые принимают в качестве аргументов другие функции. Функции map(), filter() и reduce() являются важными инструментами функционального программирования. Все они принимают на вход функцию. Такая функция-аргумент может быть обычной функцией или лямбда-функцией.
Мы уже знаем как создавать обычные функции используя "let" синтаксис:
В этой статье мы рассмотрим некоторые другие способы создания функций, а также советы по их определению.
Анонимные функции (лямбды)
Если вы знакомы с лямбдами в других языках, следующие абзацы покажутся знакомыми. Анонимные функции (или "лямбда-выражения") определяются следующим образом:
Лямбда-определение функции сложения:
Та же функция в традиционной форме:
Лямбды часто используются в виде небольших выражений или когда нет желания определять для выражения отдельную функцию. Как вы уже видели, при работе со списками это не редкость.
Обратите внимание, вокруг лямбд необходимо использовать скобки.
Так же лямбды используются, когда необходимо явно другую функцию. Например, ранее обсуждаемый " adderGenerator ", который мы обсуждали ранее может быть переписан с помощью лямбды.
Лямбда-версия немного длиннее, но сразу даёт понять, что будет возвращена промежуточная функция.
Лямбды могут быть вложенными. Еще один пример определения adderGenerator , в этот раз только на лямбдах.
Ясно ли вам, что все три определения эквивалентны?
Если нет, то перечитайте главу о каррировании. Это очень важно для понимания!
Сопоставление параметров с шаблоном
Когда определяется функция, ей можно передать параметры явно, как в примерах выше, но так же можно произвести сопоставление с шаблоном прямо в секции параметров. Другими словами, секция параметров может содержать паттерны (шаблоны сопоставления), а не только идентификаторы!
Следующий пример демонстрирует использование шаблонов в определении функции:
Данный вид сопоставления может присходить только тогда, когда соответствие всегда разрешимо. Например, сопоставлять таким образом типы объединения и списки нельзя, потому что некоторые случаи не смогут быть сопоставлены.
Компилятор выдаст предупреждение о неполноте сопоставления (пустой список вызовет ошибку в рантайме на входе в эту функцию).
Распространенная ошибка: кортежи vs. множество параметров
Если вы пришли из C-подобного языка, кортеж, использованный в качестве единственного аргумента функции, может до боли напоминать многопараметрическую функцию. Но это не одно и то же! Как я отметил ранее, если вы видите запятую, скорее всего это кортеж. Параметры же разделяются пробелами.
- Первое определение, " addTwoParams ", принимает два параметра, разделенных пробелом.
- Второе определение, " addTuple ", принимает один параметр. Этот параметр привязывает "x" и "y" из кортежа и суммирует их.
- Третье определение, " addConfusingTuple ", принимает один параметр как и " addTuple ", но трюк в том, что этот кортеж распаковывается(сопоставляется с образцом) и привязывается как часть определения параметра при помощи сопоставления с шаблоном. За кулисами все происходит точно так же, как и в " addTuple ".
Посмотрим на сигнатуры (всегда смотрите на них если в чём-то не уверены).
Здесь мы видим ошибку во втором вызове.
Во-первых, компилятор трактует (1,2) как обобщенный кортеж вида ('a * 'b) , который и пробует передать в качестве первого параметра в " addTwoParams ". После чего жалуется, что ожидаемый первый параметр addTwoParams не является int , а была совершена попытка передачи кортежа.
Что бы сделать кортеж, используйте запятую!
И наоборот, если передать несколько аргументов в функцию ожидающую кортеж, так же получите непонятную ошибку.
В этот раз, компилятор решил, что раз передаются два аргумента, addConfusingTuple должна быть каррируемой. А запись " addConfusingTuple 1 " является частичным применением и должна возвращать промежуточную функцию. Попытка вызвать эту промежуточную функцию с параметром "2" выдаст ошибку, т.к. никакой промежуточной функции нет! Мы видим ту же ошибку, что и в главе о каррировании, где мы обсуждали проблемы со слишком большим количеством параметров.
Почему бы не использовать кортежи в качестве параметров?
Следует обратить внимание, что сигнатура отличается от сигнатуры функции с тремя параметрами. Здесь только одна стрелка, один параметр и звездочки, указывающие на кортеж (int*int*int) .
Когда надо подавать аргументы отдельными параметрами, а когда кортежем?
Заметьте, данные вызовы лишь выглядят как передача кортежей, но на самом деле это особый случай. Вы не сможете передать в такие функции настоящие кортежи:
Руководство по выбору отдельных и cгруппированных параметров
Общие рекомендации о том, как структурировать параметры при проектировании собственных функций.
- В общем случае, всегда лучше использовать раздельные параметры вместо передачи одной структуры будь то кортеж или запись. Это позволяет добиться более гибкого поведения, такого как частичное применение.
- Но, когда группа параметров должна быть передана за раз, следует использовать какой-нибудь механизм группировки.
Другими словами, когда разрабатываете функцию, спросите себя "Могу ли я предоставить это параметр отдельно?". Если ответ нет, то параметры должны быть сгруппированы.
Рассмотрим несколько примеров:
Наконец, убедитесь, что порядок параметров поможет в частичном применении (смотрите руководство здесь). Например, почему я поместил myCredentials перед aName в последней функции?
Функции без параметров
Иногда может понадобиться функция, которая не принимает никаких параметров. Например, нужна функция "hello world" которую можно вызывать многократно. Как было показано в предыдущей секции, наивное определение не работает.
После чего функция всегда должна вызываться с unit аргументом:
Запомните, вызывайте их с unit параметрами!
Определение новых операторов
Можно определять функции с использованием одного и более операторных символа (смотрите документацию для ознакомления со списком символов):
Необходимо использовать скобки вокруг символов для определения функции.
Единожды определенная, новая функция может быть использована обычным способом, если будет завернута в скобки:
Если функция используется с двумя параметрами, можно использовать инфиксную операторную запись без скобок.
Можно также определять префиксные операторы начинающиеся с ! или ~ (с некоторыми ограничениями, смотрите документацию)
Point-free стиль
Мы уже видели множество примеров функций у которых отсутствовали последние параметры, чтобы снизить уровень хаоса. Этот стиль называется point-free стилем или молчаливым программированием (tacit programming).
Вот несколько примеров:
У данного стиля есть свои плюсы и минусы.
Одним из плюсов является то, что акцент производится на композицию функций высшего порядка вместо возни с низкоуровневыми объектами. Например, " (+) 1 >> (*) 2 " — явное сложение с последующим умножением. А " List.reduce (+) " дает понять, что важна операция сложения, безотносительно информации о списке.
Бесточечный стиль позволяет сосредоточиться на базовом алгоритме и выявить общие черты в коде. " reduce " функция, использованная выше, является хорошим примером. Эта тема будет обсуждаться в запланированной серии по обработке списков.
С другой стороны, чрезмерное использование подобного стиля может сделать код малопонятным. Явные параметры действуют как документация и их имена (такие как "list") облегчают понимание того, что делает функция.
Как и все в программировании, лучшая рекомендация, предпочитайте тот подход, что обеспечивает наибольшую ясность.
Комбинаторы
"Комбинаторами" называют функции, чей результат зависит только от их параметров. Это означает, что не существует зависимости от внешнего мира, и, в частности, никакие другие функции или глобальные значения не могут повлиять на них.
На практике, это означает, что комбинаторные функции ограничены комбинацией их параметров различными способами.
Мы уже видели несколько комбинаторов: "pipe"(конвейер) и оператор композиции. Если посмотреть на их определения, то понятно, что все, что они делают, это переупорядочивают параметры различными способами.
С другой стороны, функции подобные "printf", хоть и примитивны, но не являются комбинаторами, потому-что имеют зависимость от внешнего мира (I/O).
Комбинаторные птички
Комбинаторы являются основой целого раздела логики (естественно называемого "комбинаторная логика"), который был изобретен за много лет до компьютеров и языков программирования. Комбинаторная логика имеет очень большое влияние на функциональное программирование.
Чтобы узнать больше о комбинаторах и комбинаторной логики, я рекомендую книгу "To Mock a Mockingbird" Raymond-а Smullyan-а. В ней он объясняет другие комбинаторы и причудливо дает им названия птиц. Вот несколько примеров стандартных комбинаторов и их птичьих имен:
Буквенные имена вполне стандартные, так что можно ссылаться на K-комбинатор всякому, кто знаком с данной терминологией.
Получается, что множество распространенных шаблонов программирования могут быть представлены через данные стандартные комбинаторы. Например, Kestrel является обычным паттерном в fluent интерфейсе где вы делаете что-то, но возвращаете оригинальный объект. Thrush — пайп, Queer — прямая композиция, а Y-комбинатор отлично справляется с созданием рекурсивных функций.
На самом деле, существует широко известная теорема, что любая вычислимая функция может быть построена при помощи лишь двух базовых комбинаторов, Kestrel-а и Starling-а.
Библиотеки комбинаторов
Библиотеки комбинаторов — это библиотеки которые экспортируют множество комбинаторных функций, которые разработаны с учетом их совместного использования. Пользователь подобной библиотеки может легко комбинировать функции вместе, чтобы получить еще большие и сложные функции, как кубики легко.
Другое преимущество комбинаторов — они являются самым безопасным типом функций. Т.к. они не имеют зависимостей от внешнего мира, они не могут изменяться при изменении глобальной среды. Функция, которая читает глобальное значение или использует библиотечные функции, может сломаться или измениться между вызовами если контекст изменится. Этого никогда не произойдет с комбинаторами.
Рекурсивные функции
Часто функции необходимо ссылаться на саму себя из ее тела. Классический пример — функция Фибоначчи.
К сожалению, данная функция не сможет скомпилироваться:
Необходимо указать компилятору, что это рекурсивная функция используя ключевое слово rec .
Рекурсивные функции и структуры данных очень распространены в функциональном программировании, и я надеюсь посвятить этой теме целую серию позднее.
Об авторах перевода
Я решил написать эту серию статей, ибо считаю, что никто не должен сталкиваться с той стеной непонимания, с которой столкнулся когда-то я.
Ведь большинство статей написаны таки образом что, для того чтобы понять что-то в Функциональном Программировании (далее ФП), тебе надо уже знать многое в ФП. Эту статью я старался написать максимально просто — настолько понятно, чтобы её суть мог уловить мой племянник, школьник, который сейчас делает свои первые шаги в Python.
Небольшое введение
- Чистая Функция
- Функции высшего порядка
Чистая Функция — Функция которая является детерминированной и не обладает никакими побочными эффектами.
То есть чтобы функция являлась чистой она должна быть детерминированной — то есть каждый раз при одинаковом наборе аргументов выдавать одинаковый результат.
Пример детерминированной функции
И пример не детерминированной:
Каждый раз при смене дня недели (который не является аргументом функции) функция выдает разные результаты.
Самый очевидный пример не детерминированной функции это random:
Второе важное качество чистой функции это отсутствие побочных эффектов.
Функция sort_by_sort имеет побочные эффекты потому что изменяет исходный список элементов и выводит что то в консоль.
В отличии от предыдущего примера функция sort_by_sorted не меняет исходного массива и возвращает результат не выводя его в консоль самостоятельно.
Чистые функции хороши тем что:
- Они проще читаются
- Они проще поддерживаются
- Они проще тестируются
- Они не зависят от того в каком порядке их вызывать
Функции высшего порядка — в программировании функция, принимающая в качестве аргументов другие функции или возвращающая другую функцию в качестве результата.
С основами чуть чуть разобрались и теперь перейдем к следующему шагу.
Итак, начнем
Для начала надо понять следующее — что такое Функциональное Программирование вообще. Лично я знаю две самые часто упоминаемые парадигмы в повседневном программировании — это ООП и ФП.
Если упрощать совсем и объяснять на пальцах, то описать эти две парадигмы можно следующим образом:
- ООП — это Объектно Ориентированное Программирование — подход к программированию, при использовании которого объекты можно передавать в качестве параметров и использовать их в качестве значений.
- По такой логике можно установить, что ФП — подход к программированию, при использовании которого функции можно передавать другим функциям в качестве параметров и использовать функции в качестве значений, возвращаемых другими функциями… Ответ скрыт в самом названии.
Это относится и к ФП — взял какие-то данные, взял какую-то функцию, поигрался с ними и выдал что-то на выходе.
Не стану расписывать всё, иначе это будет оооочень долго. Цель данной статьи — помочь разобраться, а не объяснить, как и что работает, поэтому тут мы рассмотрим основные функции из ФП.
В большинстве своем ФП (как я его воспринимаю) — это просто упрощенное написание кода. Любой код, написанный в функциональном стиле, может быть довольно легко переписан в обычном стиле без потери качества, но более примитивно. Цель ФП заключается в том, чтобы писать код более простой, понятный и который легче поддерживать, а также который занимает меньше памяти, ну и куда же без этого — разумеется, главная вечная мораль программирования — DRY (Don’t Repeat Yourself — Не повторяйся).
Сейчас мы с вами разберем одну из основных функций, которая применяется в ФП — Lambda функцию.
В следующих статьях мы разберем такие функции как Map, Zip, Filter и Reduce.
Lambda функция
Lambda — это инструмент в python и других языках программирования для вызова анонимных функций. Многим это скорее всего ничего не скажет и никак не прояснит того, как она работает, поэтому я расскажу вам просто механизм работы lambda выражений.
Все очень просто.
Рассмотрим пример. Например, нам надо написать функцию которая бы считала площадь круга при известном радиусе.
Формула площади круга это
где
S — это площадь круга
pi — математическая константа равная 3.14 которую мы получим из стандартной библиотеки Math
r — радиус круга — единственная переменная которую мы будем передавать нашей функции
Теперь оформим это все в python:
Вроде бы неплохо, но это всё может выглядеть куда круче, если записывать это через lambda:
Чтобы было понятнее, анонимный вызов функции подразумевает то, что вы используете её, нигде не объявляя, как в примере выше.
Лямбда функция работает по следующему принципу
Рассмотрим пример с двумя входными аргументами. Например, нам надо посчитать объем конуса по следующей формуле:
Запишем это все в python:
А теперь как это будет выглядеть в lambda форме:
Количество переменных здесь никак не ограничено. Для примера посчитаем объем усеченного конуса, где у нас учитываются 3 разные переменные.
Объем усеченного конуса считается по формуле:
И вот, как это будет выглядеть в python классически:
А теперь покажем, как это будет выглядеть с lambda:
После того, как мы разобрались, как работает lambda функция, давайте разберем ещё кое-что интересное, что можно делать с помощью lambda функции, что может оказаться для вас весьма неожиданным — Сортировку.
Сортировать одномерные списки в python с помощью lambda довольно глупо — это будет выглядеть, как бряцание мускулами там, где оно совсем не нужно.
Ну серьезно допустим, у нас есть обычный список (не важно состоящий из строк или чисел) и нам надо его отсортировать — тут же проще всего использовать встроенную функцию sorted(). И в правду, давайте посмотрим на это.
В таких ситуациях, действительно, хватает обычного sorted() (ну или sort(), если вам нужно изменить текущий список на месте без создания нового, изменив исходный).
Но что, если нужно отсортировать список словарей по разным ключам? Тут может быть запись как в классическом стиле, так и в функциональном. Допустим, у нас есть список книг вселенной Песни Льда и Пламени с датами их публикаций и количеством страниц в них.
Как всегда, начнем с классической записи.
А теперь перепишем это все через lambda функцию:
Таким образом, lambda функция хорошо подходит для сортировки многомерных списков по разным параметрам.
Если вы повторите весь этот код самостоятельно, написав его сами, то я уверен, что с этого момента вы сможете сказать, что отныне вы понимаете, как работают lambda выражения, и сможете применять их в работе.
Но где же тут та самая экономия места, времени и памяти? Экономится максимум пара строк.
Конечно многие из нас знакомы с этим понятием, однако данная статья рассчитана на новичков. В данном посте постараюсь рассмотреть данный феномен и привести примеры использования. Для начала необходимо понять что же такое лямбда-функция. Итак, лямбда-функция, часто ее называют анонимной, т. е. функция при определении которой не нужно указывать ее имя. Возвращаемое значение такой функцией присваивается переменной, через которую в последствие эту функцию можно вызывать.
До выхода PHP 5.3 определять лямбда-функции было возможно, но их нельзя было назвать полноценными. Сейчас я приведу пару примеров и продолжим рассматривать данные понятия.
Конечно динамическое создание функций не решает всех проблем, однако порой написание такой одноразовой функции может быть полезным. Можно расширить наш пример:
Понятие замыкания наверняка знакомо программистам на JavaScript, а так же программистам на многих других языках. Замыкание — это функция, охватывающая или замыкающая текущую область видимости. Что бы понять все это, рассмотрим пример:
Как вы уже могли заметить, функция не имеет имени и результат присваивается переменной. Лямбда-функция, созданная таким образом, возвращает значение в виде объекта типа closure.
В PHP 5.3 стало возможно вызывать объекты как если бы они были функциями. А именно магический метод __invoke() вызывается каждый раз, когда класс вызывается как функция.
Переменные недоступны внутри функции, если они не объявлены глобальными, так же переменные из дочернего контекста недоступны если только не используется зарезервированное слово use. Обычно в PHP переменные передаются в замыкание значением, это поведение можно изменить с помощью ампермсанда перед переменной в выражении use. Рассмотрим пример:
Если убрать амперсанды то оба раза выведется 80, т. к. переменная $mul внутри замыкания будет копией, а не ссылкой.
Итак, осталось только выяснить как это можно применить на практике.
Рассмотрим пример:
Этот пример уже можно использовать для достаточно гибкого прототипирования. Достаточно объявить методы для всех SQL-операций с объектом.
Автор не призывает всех придерживаться такой практики, равно как и не считает что так лучше, все вышеописанное лишь пример использования, причем возможно не самый техничный и интересный, и не более того.
UPD Говоря о том самом длинном регулярном выражении, я не стал подписывать его в комментариях и решил вынести сюда. Оно лишь ищет строки в одинарных и двойных кавычках, а так же имена таблиц и экранирует их.
Читайте также: