Подтвердить что ты не робот

Почему карта возвращает объект карты вместо списка в Python 3?

Я заинтересован в понимании дизайна нового языка Python 3.x.

Мне нравится в Python 2.7 функция map:

Python 2.7.12
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: [2, 3, 4]

Однако в Python 3.x все изменилось:

Python 3.5.1
In[2]: map(lambda x: x+1, [1,2,3])
Out[2]: <map at 0x4218390>

Я понимаю, как, но я не мог найти ссылку на причину. Почему дизайнеры языка сделали этот выбор, который, на мой взгляд, вызывает большую боль. Было ли это для разработчиков оружия, чтобы придерживаться списков?

IMO, список можно считать естественным Functors; и меня как-то думали думать таким образом:

fmap :: (a -> b) -> f a -> f b
4b9b3361

Ответ 1

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

>>> list(map(min, [1,2,3,4], [0,10,0,10]))
[0,2,0,4]

Это немного проще, чем использование zip:

>>> list(min(x, y) for x, y in zip([1,2,3,4], [0,10,0,10]))

В противном случае он просто ничего не добавляет к выражениям генератора.

Ответ 2

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

Вы можете найти этот docs полезным, итераторы потрясающие.

Объект, представляющий поток данных. Повторные вызовы метода iterators __next__() (или передача его встроенной функции next()) возвращают последовательные элементы в потоке. Когда больше нет данных, вместо этого возникает исключение StopIteration. На этом этапе объект итератора исчерпан, и дальнейшие вызовы его методу __next__() снова поднимут StopIteration. Итераторы должны иметь метод __iter__(), который возвращает сам объект итератора, поэтому каждый итератор также можно итерабельно и может использоваться в большинстве мест, где принимаются другие итерации. Одним из примечательных исключений является код, который пытается выполнить несколько итераций. Объект-контейнер (например, list) создает новый новый итератор каждый раз, когда вы передаете его функции iter() или используете его в цикле for. Попытка этого с помощью итератора просто вернет тот же исчерпанный объект итератора, который использовался в предыдущем проходе итерации, что делает его похожим на пустой контейнер.

Ответ 3

Гвидо отвечает на этот вопрос здесь: "так как создание списка будет просто расточительным".

Он также говорит, что правильное преобразование состоит в использовании регулярного цикла for.

Преобразование map() от 2 до 3 может быть не просто простым приложением list( ) вокруг него. Гвидо также говорит:

"Если входные последовательности не имеют одинаковой длины, map() остановится при завершении кратчайших последовательностей. Для полной совместимости с map() из Python 2.x также оберните последовательности в itertools.zip_longest(), например

map(func, *sequences)

становится

list(map(func, itertools.zip_longest(*sequences)))

"

Ответ 4

В Python 3 многие функции (а не только map, но zip, range и другие) возвращают итератор, а не полный список. Вам может понадобиться итератор (например, чтобы не содержать весь список в памяти), или вам может понадобиться список (например, чтобы иметь возможность индексировать).

Однако, я думаю, что ключевой причиной изменения в Python 3 является то, что, хотя тривиально преобразовать итератор в список с помощью list(some_iterator), обратный эквивалент iter(some_list) не достигает желаемого результата, потому что полный список имеет уже построены и сохранены в памяти.

Например, в Python 3 list(range(n)) работает очень хорошо, поскольку для создания объекта range мало затрат, а затем преобразования его в список. Однако в Python 2 iter(range(n)) не сохраняется память, потому что полный список создается range() до того, как будет создан итератор.

Поэтому в Python 2 для создания итератора требуются отдельные функции, а не список, например imap для map (хотя они не совсем эквивалентны), xrange для range, izip для zip. В отличие от Python 3 требуется только одна функция, так как вызов list() создает полный список, если требуется.