Есть ли смысл использовать map() vs for?

Проводит ли map() итерацию по списку, например, "для"? Есть ли значение при использовании карты vs для?

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

for item in items:
    item.my_func()

Если это имеет смысл, я хотел бы сделать его map(). Это возможно? Какой пример?

Ответ 1

Вы можете использовать map вместо цикла for, который вы указали, но поскольку вы, похоже, не используете результат item.my_func(), не рекомендуется. map следует использовать, если вы хотите применить функцию без побочных эффектов ко всем элементам списка. Во всех других ситуациях используйте явный for-loop.

Кроме того, с Python 3.0 map возвращает генератор, поэтому в этом случае map не будет вести себя одинаково (если вы явно не оцениваете все элементы, возвращаемые генератором, например, вызывая list на нем).


Изменить: kibibu просит в комментариях пояснить, почему map первый аргумент не должен быть функцией со стороной последствия. Я дам ответ на этот вопрос:

map должна быть передана функция f в математическом смысле. В таких обстоятельствах не имеет значения, в каком порядке f применяется к элементам второго аргумента (если они возвращаются в исходном порядке, конечно). Что еще более важно, при таких обстоятельствах map(g, map(f, l)) семантически эквивалентен map(lambda x: g(f(x)), l), независимо от порядка, в котором f и g применяются к их соответствующим входам.

Например, не имеет значения, вернет ли он map и итератор или полный список сразу. Однако, если f и/или g вызывают побочные эффекты, то эта эквивалентность гарантируется только в том случае, если семантика map(g, map(f, l)) такова, что на любой стадии g применяется к первым n элементам, возвращаемым map(f, l) перед map(f, l) применяется f к элементу (n + 1) st l. (Это означает, что map должен выполнить самую ленивую возможную итерацию, которую он делает в Python 3, но не в Python 2!)

Идем дальше: даже если мы предполагаем реализацию Python 3 map, семантическая эквивалентность может легко сломаться, если вывод map(f, l) является, например, через itertools.tee перед подачей внешнего вызова map.

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

Наконец, map напоминает много людей о его подлинно функциональном аналоге в различных (чисто) функциональных языках. Передача "функции" с побочными эффектами будет путать этих людей. Следовательно, рассматривать альтернативу (т.е. Используя явный цикл) не сложнее реализовать, чем вызов map, настоятельно рекомендуется ограничивать использование map теми случаями, в которых применяется функция, применяемая не вызывает побочных эффектов.

Ответ 2

Вы можете написать это с помощью следующей карты:

map(cls.my_func, items)

заменяя cls классом элементов, которые вы повторяете.

Как упоминалось в Stephan202, в этом случае не рекомендуется.

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

Если вы не хотите создавать новый список или если функция имеет побочные эффекты, используйте цикл for. Это относится к вашему примеру.

Ответ 3

Существует небольшая смысловая разница, которая, вероятно, закрыта в спецификации языка python. Карта явно распараллеливается, тогда как только в особых ситуациях. Код может вырваться из for, но только побег с исключением из карты.

На мой взгляд, карта не должна также гарантировать порядок применения функции, пока она должна. В настоящее время AFAIK не реализует реализацию python для автоматической распараллеливания.

Ответ 4

Вы можете переключить свой map на классную или многопроцессорную или распределенную вычислительную среду, если вам нужно. Disco - пример распределенной, устойчивой к отказам фреймворка erlang-and-python. Я настроил его на 2 ящика по 8 ядер, и теперь моя программа работает в 16 раз быстрее, благодаря кластеру Disco, однако мне пришлось переписать мою программу из контекстов списка и для циклов для отображения/уменьшения.

То же самое касается написания программы, использующей для циклов и списков, а также для отображения/уменьшения, но когда вам это нужно для работы в кластере, вы можете сделать это почти бесплатно, если вы использовали map/reduce. Если вы этого не сделали, ну, вам придется переписать.

Остерегайтесь: насколько я знаю, python 2.x возвращает список вместо итератора с карты. Я слышал, что это можно обойти, используя iter.imap() (никогда не использовал его).

Ответ 5

Используйте явный цикл for-loop, когда вам не нужен список результатов (например, функции с побочными эффектами).

Используйте понимание списка, когда вам нужен список результатов назад (например, функции, возвращающие значение, основанное непосредственно на вводе).

Используйте map(), когда вы пытаетесь убедить пользователей Lisp, что Python стоит использовать.;)

Ответ 6

Основным преимуществом map является то, когда вы хотите получить результат вычисления по каждому элементу списка. Например, этот фрагмент удваивает каждое значение в списке:

map(lambda x: x * 2, [1,2,3,4])  #=> [2, 4, 6, 8]

Важно отметить, что map возвращает новый список с результатами. Он не изменяет исходный список на месте.

Чтобы сделать то же самое с for, вам нужно будет создать пустой список и добавить дополнительную строку в тело for, чтобы добавить результат каждого вычисления в новый список. Версия map более лаконична и функциональна.

Ответ 7

Карта иногда может быть быстрее для встроенных функций, чем для ручного кодирования цикла for. Попробуйте карту времени (str, range (1000000)) против аналогичного цикла.

Ответ 8

map(lambda item: item.my_func(), items)