Я никогда не полагал, что Python попадет под влияние функциональных языков, независимо от того что люди говорят или думают. Я знаком с императивными языками, такими как C и Algol68 и хотя я сделал функции объектами «первого класса», я не рассматривал Python как язык функционального программирования. Однако, было ясно, что пользователи хотят больше от списков и функций.
Операции над списками применялись к каждому элементу списка и создавали новый список. Например:
На функциональных языках, таких как Lisp и Scheme, операции, такие как эта были разработаны как встроенные функции языка. Таким образом пользователи, знакомые с такими языками, реализовывали аналогичную функциональность в Python. Например:
Тонкость вышеупомянутого кода в том, что многим людям не нравился факт, что функция применяется к элементам списка как набор отдельных функций. Языки, такие как Lisp позволили функциям определяться «налету» при маппинге. Например, в Scheme Вы можете создавать анонимные функции и выполнить маппинг в единственном выражении, используя лямбду, как ниже:
Хотя в Python функции были объектами «первого класса», у него не было никакого подобного механизма для того, чтобы создавать анонимные функции.
В конце 1993, пользователи метались вокруг различных идей, чтобы создать анонимные функции. Например, Марк Луц написал код функции, которая создает функции, используя exec:
Тим Петерс написал решениерешения, которое упростило синтаксис, разрешая пользователям следующее:
Стало ясно, что действительно появилось необходимость в такой функциональности. Одновременно, это казалось заманчиво — определить анонимные функции как строки кода, которые программист должен вручную обработать через exec. Таким образом, в январе 1994, map(), filter(), и reduce() функции были добавлены к стандартной библиотеке. Кроме того, был представлен оператор лямбды для того, чтобы создавать анонимные функции (как выражения) в более прямом синтаксисе. Например:
Эти дополнения были существенными на ранней стадии разработки. К сожалению, я не помню автора, и логи SVN не записали его. Если это Ваша заслуга, оставьте комментарий!
Мне никогда не нравилось использовать терминологию «лямбды», но из-за отсутствия лучшей и очевидной альтернативы, она была принята в Python. В конце концов это был выбор теперь анонимного автора, и в то время большие изменения требовали намного меньшего количества обсуждений чем в настоящее время.
Лямбда была предназначена действительно только, чтобы быть синтаксическим сахаром для определения анонимных функций. Однако, у такого выбора терминологии было много непреднамеренных последствий. Например, пользователи, знакомые с функциональными языками, ожидали, что семантика лямбды будет соответствовать онной из других языков. В результате они нашли, что реализации Python очень недоставало расширенного функционала. Например, проблема с лямбдой состоит в том, что предоставленное выражение не могло обратиться к переменным в окружающем контексте. Например, если бы у Вас этот код, map() прервется, потому что функция лямбды работала бы с неопределенной ссылкой на переменную 'a'.
Существовали обходные решения этой проблемы, но они заключались в использовании «аргументов по умолчанию» и передачу скрытых параметров в лямбда-выражение. Например:
«Корректное» решение этой проблемы для внутренних функций было в том, чтобы неявно перенести ссылки на все локальные переменные в контекст функции. Данный подход известен как «замыкание» и является важным аспектом функциональных языков. Однако, эта возможность не была представлена в Python до выпуска версии 2.2.
Любопытно, что map, filter, и reduce функции, которые первоначально смотивировали введение лямбды, и других функциональных возможностей были в большой степени заменены на “list comprehensions” и генераторы. Фактически, функция reduce была удалена из списка встроенных функций в Python 3.0.
Даже при том, что я не задумывал Python как функциональный язык, введение замыканий было полезно в разработке многих других возможностей языка. Например, определенные аспекты классов нового стиля, декораторов, и других современных возможностей используют замыкания.
Наконец, даже при том, что много возможностей функционального программирования были введены за эти годы, Python все еще испытывает недостаток в определенном функционале из «настоящих» функциональных языков. Например, Python не выполняет определенные виды оптимизации (например, хвостовая рекурсия). Динамический характер Python сделал невозможным ввести оптимизации времени компиляции, известные в функциональных языкых как Haskell или ML.
Операции над списками применялись к каждому элементу списка и создавали новый список. Например:
def square(x):
return x*x
vals = [1, 2, 3, 4]
newvals = []
for v in vals:
newvals.append(square(v))
На функциональных языках, таких как Lisp и Scheme, операции, такие как эта были разработаны как встроенные функции языка. Таким образом пользователи, знакомые с такими языками, реализовывали аналогичную функциональность в Python. Например:
def map(f, s):
result = []
for x in s:
result.append(f(x))
return result
def square(x):
return x*x
vals = [1, 2, 3, 4]
newvals = map(square,vals)
Тонкость вышеупомянутого кода в том, что многим людям не нравился факт, что функция применяется к элементам списка как набор отдельных функций. Языки, такие как Lisp позволили функциям определяться «налету» при маппинге. Например, в Scheme Вы можете создавать анонимные функции и выполнить маппинг в единственном выражении, используя лямбду, как ниже:
(map (lambda (x) (* x x)) '(1 2 3 4))
Хотя в Python функции были объектами «первого класса», у него не было никакого подобного механизма для того, чтобы создавать анонимные функции.
В конце 1993, пользователи метались вокруг различных идей, чтобы создать анонимные функции. Например, Марк Луц написал код функции, которая создает функции, используя exec:
def genfunc(args, expr):
exec('def f(' + args + '): return ' + expr)
return eval('f')
# Sample usage
vals = [1, 2, 3, 4]
newvals = map(genfunc('x', 'x*x'), vals)
Тим Петерс написал решениерешения, которое упростило синтаксис, разрешая пользователям следующее:
vals = [1, 2, 3, 4]
newvals = map(func('x: x*x'), vals)
Стало ясно, что действительно появилось необходимость в такой функциональности. Одновременно, это казалось заманчиво — определить анонимные функции как строки кода, которые программист должен вручную обработать через exec. Таким образом, в январе 1994, map(), filter(), и reduce() функции были добавлены к стандартной библиотеке. Кроме того, был представлен оператор лямбды для того, чтобы создавать анонимные функции (как выражения) в более прямом синтаксисе. Например:
vals = [1, 2, 3, 4]
newvals = map(lambda x:x*x, vals)
Эти дополнения были существенными на ранней стадии разработки. К сожалению, я не помню автора, и логи SVN не записали его. Если это Ваша заслуга, оставьте комментарий!
Мне никогда не нравилось использовать терминологию «лямбды», но из-за отсутствия лучшей и очевидной альтернативы, она была принята в Python. В конце концов это был выбор теперь анонимного автора, и в то время большие изменения требовали намного меньшего количества обсуждений чем в настоящее время.
Лямбда была предназначена действительно только, чтобы быть синтаксическим сахаром для определения анонимных функций. Однако, у такого выбора терминологии было много непреднамеренных последствий. Например, пользователи, знакомые с функциональными языками, ожидали, что семантика лямбды будет соответствовать онной из других языков. В результате они нашли, что реализации Python очень недоставало расширенного функционала. Например, проблема с лямбдой состоит в том, что предоставленное выражение не могло обратиться к переменным в окружающем контексте. Например, если бы у Вас этот код, map() прервется, потому что функция лямбды работала бы с неопределенной ссылкой на переменную 'a'.
def spam(s):
a = 4
r = map(lambda x: a*x, s)
Существовали обходные решения этой проблемы, но они заключались в использовании «аргументов по умолчанию» и передачу скрытых параметров в лямбда-выражение. Например:
def spam(s):
a = 4
r = map(lambda x, a=a: a*x, s)
«Корректное» решение этой проблемы для внутренних функций было в том, чтобы неявно перенести ссылки на все локальные переменные в контекст функции. Данный подход известен как «замыкание» и является важным аспектом функциональных языков. Однако, эта возможность не была представлена в Python до выпуска версии 2.2.
Любопытно, что map, filter, и reduce функции, которые первоначально смотивировали введение лямбды, и других функциональных возможностей были в большой степени заменены на “list comprehensions” и генераторы. Фактически, функция reduce была удалена из списка встроенных функций в Python 3.0.
Даже при том, что я не задумывал Python как функциональный язык, введение замыканий было полезно в разработке многих других возможностей языка. Например, определенные аспекты классов нового стиля, декораторов, и других современных возможностей используют замыкания.
Наконец, даже при том, что много возможностей функционального программирования были введены за эти годы, Python все еще испытывает недостаток в определенном функционале из «настоящих» функциональных языков. Например, Python не выполняет определенные виды оптимизации (например, хвостовая рекурсия). Динамический характер Python сделал невозможным ввести оптимизации времени компиляции, известные в функциональных языкых как Haskell или ML.