You are viewing vitus_wagner

Журнал Витуса. - Про lambda в python
[Друзья] [Свежие записи] [Dreamwidth] [Фото] [Тексты] [Друзья Ирины] [Матерные писатели] [Сообщества] [3 круг]
January 21st, 2010
09:14 pm
[User Picture]

[Link]

Previous Entry Add to Memories Share Next Entry
Про lambda в python
Вот в 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, которое на мой взгляд, куда проще и естественней читается, оказалось вторым по скорости после решения avysk, которое вообще-то решением не является, а явялется только демонстрацией одного из шагов в решении (не тот порядок сортировки, нет преобразования tuple в строку через заданный разделитель)

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

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

Tags:

(84 comments)

Comments
 
[User Picture]
From:phd
Date:January 21st, 2010 06:31 pm (UTC)
(Link)
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."
(Replies frozen) (Thread)
[User Picture]
From:vitus_wagner
Date:January 21st, 2010 06:42 pm (UTC)
(Link)
Вот собственно о том я и спрашиваю: Почему эти функции "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)

И что никто не пытался использовать оператор форматирования по шаблону для конструирования итоговой строки.
Побенчмаркать эти варианты что-ли.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:rmihael
Date:January 21st, 2010 06:42 pm (UTC)
(Link)
Отвечу за себя. У меня две личные причины и одна "общественная".
1. Давно и упорно ходят слухи (а может уже и не слухи, не следил за третьим питоном), что Гвидо таки выпилит лямбды нафиг.
2. На мой персональный вкус питоновский код с лямбдами читается хуже. Очень уж они выпирают из общего питоновского стиля. Против лямбд ничего не имею, но вот именно в питоне стараюсь обходится без них.

Общественная причина в том, что вполне конкретные студенты-стажёры, с которыми приходилось работать, обычно догадываются куда надо посмотреть на тему operator.itemgetter, а вот лямбда вгоняет их в ступор. Причину этого странного выверта ещё предстоит изучить психологам.
(Replies frozen) (Thread)
[User Picture]
From:vitus_wagner
Date:January 21st, 2010 06:44 pm (UTC)
(Link)
Причину этого выверта не надо изучать психологам. Она проста - этих студентов никогда не учили ни лямда-исчислению в курсе математики, ни Lisp-у в курсе программированя.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:vitus_wagner
Date:January 21st, 2010 06:48 pm (UTC)
(Link)
А что Гвидо выкинет лямбды - я не верю. Потому что примерно год назад MIT перешел в своем CS-курсе со схемы на python. Соответственно, если кто-то попытается выкинуть лямбды из питона, профессора MIT забьют его пляжными тапочками. Ибо за 60 лет преподавания lisp-а привыкли к лямбдам.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:amarao_san
Date:January 21st, 2010 07:07 pm (UTC)
(Link)
не от django ли? Там в некоторых случаях, только им и обходишься. А ещё метаклассами.
(Replies frozen) (Thread)
[User Picture]
From:python_breeder
Date:January 21st, 2010 07:17 pm (UTC)
(Link)
Правильный ответ:


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

(Replies frozen) (Thread)
[User Picture]
From:vitus_wagner
Date:January 21st, 2010 07:19 pm (UTC)
(Link)
А-а-а, pattern matching!!! Это питон или erlang какой?!!
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:gegmopo4
Date:January 21st, 2010 08:40 pm (UTC)
(Link)
Здесь распаковка кортежа излишня.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:dragsan
Date:January 21st, 2010 07:55 pm (UTC)
(Link)
Кажется тут небольшая путаница.

operator.getitem != operator.itemgetter
(Replies frozen) (Thread)
[User Picture]
From:gegmopo4
Date:January 21st, 2010 08:00 pm (UTC)
(Link)
Лямбда считается некошерной и её даже собирались убрать. Главная причина — убогость питоновской лямды. Жалеть не нужно, все случаи использования лямбды легко переписываются с использованием локальных именованных функций. Это и читабельнее, и мощнее.

Этот пример, например, можно решить таким способом.
def sortkey(x):
return x[1]
print ['%s %s' % x for x in sorted(d.items(), key = sortkey, reverse = True)]
(Replies frozen) (Thread)
From:pavla_dar
Date:January 21st, 2010 09:22 pm (UTC)

Ненавижу...

(Link)
Ненавижу именованные сущности, используемые не более, чем полтора раза.
Ненавижу, когда эран заполнен не алгоритмом, а флудом, дабы ублажить тупой компилятор и ограниченный язык.
Ненавижу С++/java за класс или обобщенный класс на каждый чих.
И люблю лямбы за их компактность, локальность, уместность и скромность.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:frotmnenogi
Date:January 21st, 2010 09:30 pm (UTC)
(Link)
на самом деле "key=lambda|sortkey" - лишнее, поскольку двуместные кортежи сортируются начиная с первого ключа. То есть извлечение ключа очень прозрачно интегрированно в операцию сравнения кортежей (поскольку первый ключ не повторяется, то дальше проверки первого элемента операция сравнения не пойдет).
(Replies frozen) (Parent) (Thread)
From:lazyreader
Date:January 21st, 2010 10:14 pm (UTC)
(Link)
Вот в том-то и проблема, что именованных.

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

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

Сегодня нет такого Дийкстры, который мог бы объяснить хомякам, что любой именованный объект в программе - это не что иное, как та же метка.
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:ramendik
Date:January 21st, 2010 09:17 pm (UTC)
(Link)
Вариант с lambda нечитаем для тех, кто не понимает этой концепции. Например, для меня.

(В питонной постановке задачи читабельность важнее скорости)
(Replies frozen) (Thread)
[User Picture]
From:arilou
Date:January 21st, 2010 10:49 pm (UTC)
(Link)
А что такого в той концепции? Ну кроме того, что надо залезть в руководство и прочитать, что означает слово 'lambda'?
(Replies frozen) (Parent) (Thread) (Expand)
[User Picture]
From:astoon
Date:January 22nd, 2010 01:47 am (UTC)
(Link)
Лямба сейчас не кошерна среди пайтонистов. Т.е. тут скорее дело моды.

Сам Гвидо высказывался не раз за убрать ее нафиг. По причине "ухудшает читаемость кода". Ссылку не приведу, но это конкретно его слова.
(Replies frozen) (Thread)
(Deleted comment)
[User Picture]
From:vitus_wagner
Date:January 22nd, 2010 06:56 am (UTC)
(Link)
Вот это я как раз и пытаюсь понять. Как использование функций из стандартной библиотеки вместо лямбды совместимо с философией "явное лучше неявного". По моему лямбда - это явное написание того что надо сделать. Вызов функции - ссылка на то, что где-то в другом месте написано что надо сделать (неявное).

Почему столько народу и в том, и в этом треде убеждены в обратном - я не понимаю.
(Replies frozen) (Parent) (Thread) (Expand)
(Deleted comment)
[User Picture]
From:_winnie
Date:January 22nd, 2010 08:44 am (UTC)
(Link)
Забавно. Мне в C++ люто не хватало лямбд для STL-алгоритмов. Их эмуляция объектами-функциями или boost::bind была длинной и нечитабельной. Поэтому нелюбовь к ним очень странной кажется :)

Вариант с лямбдой мне тоже кажется более приятным - используется более универсальная кросс-языковая концепция, чем языко-специфичный import из operator, не дающий глобального знания. Студенту, знакомому с лямбдами, в этом случае не понадобится лезть в документацию.
(Replies frozen) (Thread)
[User Picture]
From:trueblacker
Date:January 22nd, 2010 08:56 pm (UTC)
(Link)
> Забавно. Мне в C++ люто не хватало лямбд для STL-алгоритмов. Их эмуляция объектами-функциями или boost::bind была длинной и нечитабельной. Поэтому нелюбовь к ним очень странной кажется :)

+100500
(Replies frozen) (Parent) (Thread)
From:lazyreader
Date:January 25th, 2010 04:37 am (UTC)
(Link)
Вот, грозятся ввести; unixtime не успеет переполниться, как в C++ будут лямбды.
(Replies frozen) (Parent) (Thread)
[User Picture]
From:love5an
Date:January 25th, 2010 06:23 pm (UTC)
(Link)
Для нормальных лямбд, в т.ч. умеющих лексические замыкания, к примеру, нужен GC.
В C++ GC нет и не будет.

И вообще, хватит издеваться над трупом.
(Replies frozen) (Parent) (Thread)
From:nonstop [blogspot.com]
Date:January 22nd, 2010 09:03 am (UTC)

хмм

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

Вроде бы нагляднее некуда: генератор + сортировка.
Потом поглядел на ваше - очень похоже.
(Replies frozen) (Thread)
[User Picture]
From:potan
Date:January 22nd, 2010 11:10 am (UTC)

Re: хмм

(Link)
-cmp(x[1], y[1]) не то же самое, что cmp(y[1], x[1])?
(Replies frozen) (Parent) (Thread) (Expand)
My Website Powered by LiveJournal.com