Комментарии 25
Упустили как минимум generator expressions и обычные генераторы (с yield).
как вообще можно сравнивать list comprehension и около генераторное выражение обернутое в лист? или сравнивайте корректно строго на 2.7 или вместо list comprehension используйте генератор обернутый в лист. а то получается попытка сравнить несравнимое и впихнуть невпихуемое.
Если Вам не требуются все вычисленные значения сразу (а может и вообще не потребуются), то Вам стоит остановить свой выбор на map.
Непонятно, почему вы сравниваете с list expressions, а не с generator expressions.
Питонячий dis даёт разницу в инструкции CALL_FUNCTION. Она отсутсвует в вашем примере
List comprehension удобнее тем, что фильтрацию удобно вставлять
Такжеgenerator-comprehension generator-expression можно делать подобным образом.
[x*x for x in values]
. Добавьте её туда для более корректного сравнения$ python -m timeit -r 10 -s "a = lambda x: x*x" "list(map(a, range(1000000)))"
$ python -m timeit -r 10 -s "a = lambda x: x*x" "[a(x) for x in range(1000000)]"
List comprehension удобнее тем, что фильтрацию удобно вставлять
[a(x) for x in range(1000000) if x%2 == 0]
list(map(a, filter(lambda x: x%2 == 0, range(1000000))))
Также
(x*x for x in range(10))
Также generator-comprehension можно делать подобным образом.Терминологически несколько неоднозначно его обозвали.
(x*x for x in range(10))
То что вы написали generator expression, a не comprehension. Разница принципиальная, те генераторы которые comprehensions (list, set, dictionary) пишутся в квадратных скобках и выдают всю коллекцию, а те которые generator expression (как в вашем примере) — по одному элементу при каждом обращении.
Да. «generator comprehension» — это просто путаница. Есть только
Generator expressions and list comprehensions.
Generator expressions and list comprehensions.
Очень поверхностная статья не раскрывающая все многообразие функционала для генерации списков (и других коллекций) в Python
Питон не тот язык где уместны такие «оптимизации», питон для тех случаев когда читаемостью кода жертвовать нельзя, именно поэтому списковые включения нужно использовать всегда и это официальная рекомендация, что кстати намекает что автор что-то неправильно замерял — уверен что списковые включения как минимум не медленнее чем map.
если учитывать, что map в 3м питоне превратился в генератор, то разница между ними все таки ощутимая. асимтоматика перебора значений так и останется линейной в обоих случаях, а вот по памяти и скорости инициализации любой генератор утрет нос list comprehension'y.
Гуидо не согласен:
In addition, the list comprehension executes much faster than the solution using map and lambda. This is because calling a lambda function creates a new stack frame while the expression in the list comprehension is evaluated without creating a new stack frame.
с этим я спорить не собираюсь, в условиях что мы хотим сделать что-то простое как x+1. однако это не отменяет сказанного мной: генератор иниализируется быстрее полного построения готового списка, памяти требует примерно ноль, асимтоматика перебора значений линейная в обоих случаях. однако, если проводить честные замеры, то в list comprehension мы обязаны вызывать какую-нибудь функцию, не потому, что так надо, а банально для чистоты эксперимента тк вызов функции одна из самых дорогих операций и просто взять ее, выкинуть и сказать что генераторы отстой — это как сказать что запорожец с реактивным двигателем быстрее болида формулы 1.
Так это о другом — конечно не надо строить весь список если его можно не строить, например не нужен доступ по индексу, тогда можно юзать generator expression зачем map?
Но если без лямбды то какой-то мизер можно получить:
map may be microscopically faster in some cases (when you're NOT making a lambda for the purpose, but using the same function in map and a listcomp).
map — это не совсем генератор. У него нет, например, метода send.
Это питон. Тут надо биться не за производительность*, а за простоту и понятность кода.
- Разумеется, не охреневая до O(n²) вместо O(n) или сжирания кучи памяти на ровном месте.
Если мне память не изменяет, то разработчики питона давно рекомендуют использовать list comprehensions вместо map, filter и прочего. По крайней мере при мирграции на третий питон утилитка 2to3 старалась заменять map & filter на них.
Автор ниасилил мануал. Даже статью написал, хы.
помню костылял сверхбыстрый файлменеджер для старой нокиии на симбе, было весело. В результате — список из 800+ файлов и папок, причем сперва папки, все в алфавитном порядке и за 0.2 секунды.
помню костылял сверхбыстрый файлменеджер для старой нокиии на симбе, было весело. В результате — список из 800+ файлов и папок, причем сперва папки, все в алфавитном порядке и за 0.2 секунды.
С приходом Python 3.8 и PEP 572, пользы от генераторов и list/set/dict comprehension стало куда больше, нежели от map/filter.
Даже интересно стало, что за книжки такие, которые кричат об обязательности использования map? Гвидо ван Россум называет map ошибкой и призывает использовать вместо него включения. Дэвид Бизли недавно написал «I can't even remember the last time I used map. 1999? It was a long time ago to be sure.»
Статья в духе "я продолжаю начинать изучать программирование". Автор копнул глубоко — в дизассемблер байткода, и в то же время безумно поверхностно:
- Не рассмотрены generator expressions
- Выбор между map и list/generator expression определяется в первую очередь сложностью обработки каждого элемента. Одно дело, если каждый элемент надо возвести в квадрат, и совсем другое дело, если для каждого элемента нужно сходить в базу, потом в сторонний сервис, а ещё это залогировать
ваш п.2 порождает классические O(N^2) алгоритмы, когда на каждый айтем в списке нужно заново делать монструозные действия по одному, связанные с вводом-выводом и задержкой
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
List Comprehension vs Map