Виктор "Витус" Вагнер ([info]vitus_wagner) wrote,

Про lambda в python

Вот в [info]ru_python поставили задачу - имеется словарь. Выдать список строк вида
"ключ: значение", отсортированный порядке убывания значений.
Поскольку питон я знаю плохо, попробовал порешать.

Поскольку питон, опять таки знаю плохо, сначала придумал ответ на perl

map("$_: $x{$_}",sort($x{b}<=>$x{a},keys %hash));

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

Получилось:

[ x+" "+str(d[x]) for x in sorted( d.keys(), key=lambda(x): -d[x]]

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

[ x[0]+" "+str(x[1]) for x in sorted(d.items(), key=lambda(x): -x[1]]

НА сем и успокоился, и стал читать решения других читателей сообщества. Обнаружил что все как один испольуют вместо lambda импорт из модуля operator

from operator import getitem;

... key=getitem(1)


getitem описан как функция с двумя элементами. То есть тут еще и currying используется. Почему это для всех питонистов, соизволивших ответить на этот вопрос, сочетание импорта модуля, который фактически лезет куда-то в потроха интерпретатора, вроде перлового Opcode с currying кажется куда более естественным, чем старая добрая lambda?

Кто-то там собрался и провел бенчмарки, так мое решение с lambda, которое на мой взгляд, куда проще и естественней читается, оказалось вторым по скорости после решения [info]avysk, которое вообще-то решением не является, а явялется только демонстрацией одного из шагов в решении (не тот порядок сортировки, нет преобразования tuple в строку через заданный разделитель)

Правда, у человека который предложил самое быстрое решение с getitem-ом испольузется кроме sorted еще и reversed, в то время как мне lambda позволяет просто поменять знак у ключей.

Господа питонисты, объясните откуда такая любовь к getitem-у берется.
Tags: компьютерное

  • 88 comments

[info]phd

January 21 2010, 18:31:31 UTC 2 years ago

PEP 290, официальный документ: http://www.python.org/dev/peps/pep-0290/#replacing-common-uses-of-lambda

"The new functions run faster and are considered by some to improve readability."

[info]vitus_wagner

January 21 2010, 18:42:48 UTC 2 years ago

Вот собственно о том я и спрашиваю: Почему эти функции "considered by some to improve readability"?

А насчет run faster - тут облом. Поскольку тут лямбда делает две вещи сразу, реализация, которая использует две функции из
PEP 290 - getitem и reversed оказывается медленнее, чем реализация, использущая ОДНУ лямбду. Видимо

lamda x: -x[1] - это uncommon use of lamda.

Странно что никому не пришло в голову использовать

sorted(d.items,key=getitem(1),reverse=True)

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

[info]phd

2 years ago

[info]beldmit

2 years ago

[info]phd

2 years ago

[info]lazyreader

2 years ago

[info]rmihael

January 21 2010, 18:42:10 UTC 2 years ago

Отвечу за себя. У меня две личные причины и одна "общественная".
1. Давно и упорно ходят слухи (а может уже и не слухи, не следил за третьим питоном), что Гвидо таки выпилит лямбды нафиг.
2. На мой персональный вкус питоновский код с лямбдами читается хуже. Очень уж они выпирают из общего питоновского стиля. Против лямбд ничего не имею, но вот именно в питоне стараюсь обходится без них.

Общественная причина в том, что вполне конкретные студенты-стажёры, с которыми приходилось работать, обычно догадываются куда надо посмотреть на тему operator.itemgetter, а вот лямбда вгоняет их в ступор. Причину этого странного выверта ещё предстоит изучить психологам.

[info]vitus_wagner

January 21 2010, 18:44:11 UTC 2 years ago

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

[info]karpion

2 years ago

[info]karpion

2 years ago

[info]karpion

2 years ago

[info]karpion

2 years ago

[info]tzirechnoy

2 years ago

[info]taris_marh

2 years ago

[info]yurikhan

2 years ago

[info]kouzdra

2 years ago

[info]kouzdra

2 years ago

[info]gegmopo4

2 years ago

[info]kouzdra

2 years ago

[info]beldmit

2 years ago

[info]potan

2 years ago

[info]nolar

2 years ago

[info]rmihael

2 years ago

[info]kostoprav

2 years ago

[info]ex_vdom

2 years ago

[info]vitus_wagner

January 21 2010, 18:48:53 UTC 2 years ago

А что Гвидо выкинет лямбды - я не верю. Потому что примерно год назад MIT перешел в своем CS-курсе со схемы на python. Соответственно, если кто-то попытается выкинуть лямбды из питона, профессора MIT забьют его пляжными тапочками. Ибо за 60 лет преподавания lisp-а привыкли к лямбдам.

[info]lazyreader

2 years ago

[info]b_al_u

2 years ago

[info]amarao_san

January 21 2010, 19:07:02 UTC 2 years ago

не от django ли? Там в некоторых случаях, только им и обходишься. А ещё метаклассами.

[info]python_breeder

January 21 2010, 19:17:02 UTC 2 years ago

Правильный ответ:


["%s: %s" % (key, value) for key, value in sorted(sdict.items(), key=lambda x: x[1], reverse=True)]

[info]vitus_wagner

January 21 2010, 19:19:19 UTC 2 years ago

А-а-а, pattern matching!!! Это питон или erlang какой?!!

[info]besm6

2 years ago

[info]wizzard0

2 years ago

[info]ramendik

2 years ago

[info]dmzlj

2 years ago

[info]gegmopo4

January 21 2010, 20:40:01 UTC 2 years ago

Здесь распаковка кортежа излишня.

[info]gegmopo4

2 years ago

[info]dragsan

January 21 2010, 19:55:06 UTC 2 years ago

Кажется тут небольшая путаница.

operator.getitem != operator.itemgetter

[info]gegmopo4

January 21 2010, 20:00:26 UTC 2 years ago

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

Этот пример, например, можно решить таким способом.
def sortkey(x):
return x[1]
print ['%s %s' % x for x in sorted(d.items(), key = sortkey, reverse = True)]

[info]pavla_dar

January 21 2010, 21:22:49 UTC 2 years ago

Ненавижу...

Ненавижу именованные сущности, используемые не более, чем полтора раза.
Ненавижу, когда эран заполнен не алгоритмом, а флудом, дабы ублажить тупой компилятор и ограниченный язык.
Ненавижу С++/java за класс или обобщенный класс на каждый чих.
И люблю лямбы за их компактность, локальность, уместность и скромность.

[info]sv_alex_13

2 years ago

[info]gegmopo4

2 years ago

[info]gegmopo4

2 years ago

[info]silly_sad

2 years ago

[info]frotmnenogi

January 21 2010, 21:30:08 UTC 2 years ago

на самом деле "key=lambda|sortkey" - лишнее, поскольку двуместные кортежи сортируются начиная с первого ключа. То есть извлечение ключа очень прозрачно интегрированно в операцию сравнения кортежей (поскольку первый ключ не повторяется, то дальше проверки первого элемента операция сравнения не пойдет).

[info]lazyreader

January 21 2010, 22:14:50 UTC 2 years ago

Вот в том-то и проблема, что именованных.

Жалко, что так мало людей понимают вред от наличия излишних имён в программе.

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

Сегодня нет такого Дийкстры, который мог бы объяснить хомякам, что любой именованный объект в программе - это не что иное, как та же метка.

[info]gegmopo4

2 years ago

[info]lazyreader

2 years ago

[info]potan

2 years ago

[info]potan

2 years ago

[info]netch

2 years ago

[info]gegmopo4

2 years ago

[info]lazyreader

2 years ago

[info]netch

2 years ago

[info]ramendik

January 21 2010, 21:17:46 UTC 2 years ago

Вариант с lambda нечитаем для тех, кто не понимает этой концепции. Например, для меня.

(В питонной постановке задачи читабельность важнее скорости)

[info]arilou

January 21 2010, 22:49:35 UTC 2 years ago

А что такого в той концепции? Ну кроме того, что надо залезть в руководство и прочитать, что означает слово 'lambda'?

[info]arilou

2 years ago

[info]astoon

January 22 2010, 01:47:48 UTC 2 years ago

Лямба сейчас не кошерна среди пайтонистов. Т.е. тут скорее дело моды.

Сам Гвидо высказывался не раз за убрать ее нафиг. По причине "ухудшает читаемость кода". Ссылку не приведу, но это конкретно его слова.

[info]freewara

January 22 2010, 04:14:56 UTC 2 years ago

Пайтон-философия "явное лучше неявного" подразумевает ответ на ваш вопрос.
То есть тот метод, который удобнее разработчику и лучше (привычнее) читаем - будет являться более правильным.

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

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

[info]vitus_wagner

January 22 2010, 06:56:15 UTC 2 years ago

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

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

[info]freewara

2 years ago

[info]freewara

2 years ago

[info]b_al_u

2 years ago

[info]freewara

2 years ago

[info]gegmopo4

2 years ago

[info]_winnie

January 22 2010, 08:44:51 UTC 2 years ago

Забавно. Мне в C++ люто не хватало лямбд для STL-алгоритмов. Их эмуляция объектами-функциями или boost::bind была длинной и нечитабельной. Поэтому нелюбовь к ним очень странной кажется :)

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

[info]trueblacker

January 22 2010, 20:56:04 UTC 2 years ago

> Забавно. Мне в C++ люто не хватало лямбд для STL-алгоритмов. Их эмуляция объектами-функциями или boost::bind была длинной и нечитабельной. Поэтому нелюбовь к ним очень странной кажется :)

+100500

[info]lazyreader

January 25 2010, 04:37:28 UTC 2 years ago

Вот, грозятся ввести; unixtime не успеет переполниться, как в C++ будут лямбды.

[info]love5an

January 25 2010, 18:23:00 UTC 2 years ago

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

И вообще, хватит издеваться над трупом.

[info]nonstop [blogspot.com]

January 22 2010, 09:03:00 UTC 2 years ago

хмм

Я поковырявшись придумал вот такое:
["{0} {1}".format(x, y) for x, y in sorted(lst.items(), cmp = lambda x, y: -cmp(x[1], y[1]))]

Вроде бы нагляднее некуда: генератор + сортировка.
Потом поглядел на ваше - очень похоже.

[info]potan

January 22 2010, 11:10:53 UTC 2 years ago

Re: хмм

-cmp(x[1], y[1]) не то же самое, что cmp(y[1], x[1])?
  • 88 comments
Create an Account
Forgot your login or password?
Facebook Twitter More login options
English • Español • Deutsch • Русский…