Почему map возвращает объект map вместо списка в 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.х все изменилось:

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

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

ИМО, список можно, естественно, думал, как функторы; и мне почему-то казалось, что я думаю так:

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

4 ответа:

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

>>> 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]))

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

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

вы можете найти docs полезно, итераторы являются удивительными.

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

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

он также говорит, что правильное преобразование использовать обычный for петли.

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

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

map(func, *sequences)

становится

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

"

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

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

например, в Python 3 list(range(n)) работает просто отлично, мало затрат на строительство