Я заинтересован в понимании нового дизайна языка в 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>
Я понимаю как, но я не мог найти ссылку на почему. Почему разработчики языка сделали этот выбор, который, на мой взгляд, приносит много боли. Было ли это для того, чтобы разработчики пытались заставить разработчиков придерживаться списка понятий?
ИМО, список естественно рассматривать как Функторы ; и меня почему-то думали так:
fmap :: (a -> b) -> f a -> f b
python
python-3.x
NoIdeaHowToFixThis
источник
источник
map
просто повторяется результат. Создание списка, когда он вам не нужен, неэффективно, поэтому разработчики решилиmap
полениться. Здесь можно многое получить для повышения производительности и не так много потерять (если вам нужен список, просто попросите его ...list(map(...))
).Ответы:
Я думаю , что причина , почему карта до сих пор существует вообще , когда выражение генератора также существует, в том , что он может принимать несколько аргументов итератора, которые все накинет и передаются в функцию:
>>> 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]))
В противном случае он просто ничего не добавляет к выражениям генератора.
источник
c = list(map(max, [1,2,3,4], [0,10,0,10, 99]))
в Python 2 и в Python 3.Поскольку он возвращает итератор, он не сохраняет полный список в памяти. Так что вы можете легко перебирать его в будущем, не причиняя боли памяти. Возможно, вам нужен даже не полный список, а его часть, пока ваше состояние не будет достигнуто.
Вы можете найти эту документацию полезной, итераторы потрясающие.
источник
Гвидо отвечает на этот вопрос здесь : « поскольку создание списка было бы расточительным ».
Он также говорит, что правильное преобразование - использовать обычный
for
цикл.Преобразование
map()
из 2 в 3 может быть не простым случаем наклеиванияlist( )
вокруг него. Гвидо также говорит:"Если входные последовательности не равной длины,
map()
остановится на завершении самой короткой из последовательностей. Для полной совместимости сmap()
Python 2.x также оберните последовательностиitertools.zip_longest()
, напримерmap(func, *sequences)
становится
list(map(func, itertools.zip_longest(*sequences)))
"
источник
map()
вызывается для побочных эффектов функции , а не для ее использования в качестве функтора.zip_longest
неверно. вы должны использоватьitertools.starmap
для того , чтобы быть эквивалентным:list(starmap(func, zip_longest(*sequences)))
. Это потому, чтоzip_longest
создает кортежи, поэтому вместо отдельных аргументов, как в случае вызова,func
будетn
получен единственный аргумент -uple .n
map(func, *sequences)
В Python 3 много функций (не только ,
map
ноzip
,range
и другие) возвращает итератор , а не полный список. Вам может понадобиться итератор (например, чтобы не хранить весь список в памяти) или список (например, чтобы иметь возможность индексировать).Однако я думаю, что основная причина изменения в Python 3 заключается в том, что, хотя преобразование итератора в список с использованием
list(some_iterator)
обратного эквивалента тривиально,iter(some_list)
не приводит к желаемому результату, поскольку полный список уже создан и хранится в памяти.Например, в Python 3 все
list(range(n))
работает нормально, поскольку созданиеrange
объекта и его последующее преобразование в список не требуют больших затрат . Однако в Python 2iter(range(n))
память не сохраняется, поскольку полный список создаетсяrange()
до построения итератора.Следовательно, в Python 2 для создания итератора требуются отдельные функции, а не список, например
imap
formap
(хотя они не совсем эквивалентны ),xrange
forrange
,izip
forzip
. В отличие от этого Python 3 требует только одной функции, поскольку приlist()
вызове создается полный список, если это необходимо.источник
itertools
итераторами возврата. Кроме того, я бы не рассматривал итераторы как ленивые списки, поскольку списки можно повторять несколько раз и обращаться к ним случайным образом.map
объектов Python 3 естьnext()
метод.range
Я знаю, что объекты диапазона Python 3 не являются строго итераторамиfoo = map(lambda x: x, [1, 2, 3])
возвращает объект картыfoo
. выполнениеfoo.next()
возвращается с ошибкой:'map' object has no attribute 'next'
__
, зарезервированы для Python; без этой оговорки у вас возникнет проблема с различением вещей, для которыхnext
является просто методом (на самом деле они не итераторы), и вещей, которые являются итераторами. На практике вам следует пропустить методы и просто использоватьnext()
функцию (напримерnext(foo)
), которая правильно работает на каждой версии Python, начиная с 2.6. Это тот же самый способ, которым вы пользуетесь,len(foo)
хотя онfoo.__len__()
будет работать нормально; методы dunder обычно предназначены для вызова не напрямую, а неявно как часть какой-либо другой операции.