Вы тут сравниваете яблоки с апельсинами. range
не просто ленивая итерация. Это конкретный объект, содержимое которого подчиняется определенным законам, что позволяет выполнять множество операций, фактически не создавая в памяти огромную последовательность. Это потому, что n-й элемент range
в основном просто start + n*step
(по модулю stop
, знаки и т. д.)
Однако map
предназначен для работы с любой функцией f
. В частности, функции могут иметь совместно используемое/глобальное состояние, которое уже исключает любую возможность выполнения map(f, something)[100]
без выполнения 100 вызовов функций. В противном случае нарушается правильность результата.
map
ленивый просто означает, что он не сразу создает полный список результатов, а ждет, пока вы потребуете следующий результат, прежде чем вызывать f
и производить его. Это позволяет избежать создания ненужных списков в коде, например:
for x in map(f, iterable):
# do something with x
где, если бы map
стремился, он бы потреблял вдвое больше памяти, чем iterable
, чтобы выполнить цикл, с ленивым map
единственное требуемое пространство - это в основном x
.
Кроме того, он позволяет вызывать map
для бесконечных итераций, таких как count()
. Это, очевидно, приводит к тому, что бесконечная программа что-то делает, или в какой-то момент вы можете просто перестать заглядывать в map
. Нетерпеливый map
не может справиться с этим делом.
Если вы хотите использовать свою собственную ограниченную карту, которая работает только с чистыми функциями и разрешает произвольный доступ, вы можете написать свой собственный класс:
class PureMap:
def __init__(self, function, sequence):
self._f = function
self._sequence = sequence
def __iter__(self):
return map(self._f, self._sequence)
def __getitem__(self, i):
return self._f(self._sequence[i])
# etc.
Однако даже в этом случае у вас есть некоторые проблемы:
Если sequence
на самом деле является iterable
, чтобы получить n-й элемент, вам нужно использовать первые n элементов. После этого вам нужно будет сохранить их как последовательность в вашем классе для будущего использования. Но это уже противоречит цели всего, так как выполнение PureMap(f, sequence)[1000]
требует от вас хранить 1000
элементов в памяти в любом случае, хотя при этом избегаются 999
вызовы f
.
Вы хотите избежать многократного вызова f
для одного и того же элемента. Это означает, что вам также придется отслеживать, какой элемент уже вычислен, а какой нет.
Единственная ситуация, в которой вы можете достичь того, чего хотите, заключается в следующем:
- Вызываемая функция чистая
- Итерируемый аргумент — это что-то вроде
range
, который разрешает произвольный доступ без необходимости создавать другие элементы.
- Функция, которую вы вызываете, работает быстро, так что вы можете пересчитать ее для различных элементов, не слишком беспокоясь о производительности.
Когда все эти предположения соблюдены, вы можете получить объект карты, который «работает как range
».
person
Bakuriu
schedule
24.05.2016
x ** 2
, в этом случае просто выполните10000 ** 2
), вы не можете индексировать его. Лень является преимуществом, потому что вам не нужно держать весь список в памяти сразу. - person jonrsharpe   schedule 24.05.2016map
в вашем примере ничуть не лучше, чем итерация по эквивалентному выражению генератора. Оба оцениваются лениво. Преимущество по сравнению со списком состоит в том, что вы не сохраняете весь список (что может быть ненужным или даже невозможным), что является преимуществом только в том случае, если он вам не нужен весь сразу. Непонятно, о чем вы пытаетесь спросить:map
или список?map
против выражения генератора? Если вам не нужноmap
, просто не беспокойтесь. Если вы предпочитаете синтаксис с выражением генератора, используйте его. - person jonrsharpe   schedule 24.05.2016x = 0; def f(y): global x; x+= 1; return x+y
, а затемmap(f, iterable)
. Теперь значение 10000-го элемента требует оценки всех предыдущих вызововf
(из-за изменения общего состояния между вызовами), поэтому, если вам действительно нужен ленивыйmap
, где вы можете получить доступ к n-му элементу, не выполняя предыдущие вызовы, вы уже ограничиваете его, чтобы иметь только чистые функции в качестве аргументов. - person Bakuriu   schedule 24.05.2016for x in map(f, iterable): print(x)
, еслиmap
лениво, требуемая память - это только место для одного элемента вiterable
, результат (x
). Если быmap
не был ленив, ему пришлось бы сначала построить полный список значений (который может быть огромным). На самом деле считают:from itertools import count; for x in map(lambda x:x+1, count()): print(x)
. С ленивой картой это печатает числа1\n2\n3...
до бесконечности, еслиmap
не ленив, этот код просто убьет ваш компьютер, поскольку вы не можете построить бесконечный список в памяти. - person Bakuriu   schedule 24.05.2016range
, но я думаю, что это было просто принятие желаемого за действительное. - person zephyr   schedule 24.05.2016