Вопрос

Map() перебирает список, как это делает «for»?Есть ли смысл использовать карту vs for?

Если да, то сейчас мой код выглядит так:

for item in items:
    item.my_func()

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

Это было полезно?

Решение

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

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


Редактировать: кибибу просит в комментариях уточнить, почему 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 применяется к первому н элементы, возвращаемые map(f, l) до map(f, l) применяется f к (п + 1)​й элемент l.(Означающий, что map должен выполнить самую ленивую итерацию — что и происходит в Python 3, но не в Python 2!)

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

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

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

Другие советы

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

map(cls.my_func, items)

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

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

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

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

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

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

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

Это то же самое, что написать программу, использующую циклы for, понимание списков и карту/сокращение, но когда вам нужно, чтобы она работала в кластере, вы можете сделать это почти бесплатно, если вы использовали карту/сокращение.Если Вы этого не сделали, что ж, Вам придется переписать.

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

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

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

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

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

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

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

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

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

map(lambda item: item.my_func(), items)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top