You are comparing apples to oranges here. range
is not just a lazy iterable. It is a specific object whose contents satisfy specific laws that allow to support many operations without actually building a huge sequence in memory. That's because the nth element of range
is basically just start + n*step
(modulo stop
, signs etc.)
However map
is meant to work with any function f
. In particular functions may have shared/global state which already defeats any chance of being able to do map(f, something)[100]
without performing 100 function calls. Not doing so breaks the correctness of the result.
map
is lazy simply means it doesn't immediately build a complete list of results but waits for you to require the next result before doing the call to f
and produce it. This avoid building unneccessary lists in code like:
for x in map(f, iterable):
# do something with x
where if map
was eager it would consume twice the memory of iterable
to do the loop, with a lazy map
the only space required is that of x
basically.
Moreover it allows to call map
on infinite iterables like count()
. This obviously result in a never ending program doing something, or at some point you can just stop looking into map
. An eager map
cannot handle this case.
If you want to use your own restricted map that works only on pure fuctions and that allow random access you could write your own class:
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.
However even in this case you have some problems:
If sequence
is actually an iterable
to obtain the nth element you have to consume the first n elements. After that you'd have to store them as a sequence in your class for future use. But this already defeats the purpose of the whole thing since doing PureMap(f, sequence)[1000]
requires you to store 1000
elements in memory anyway, even though it avoids 999
calls to f
.
You want to avoid calling f
multiple times on the same element. This means you'd also have to keep track of which element was already computed and which not.
The only situation where you could achieve what you want is the following:
- The function being called is pure
- The iterable argument is something like
range
that allows random access without having to produce other elements
- The function you call is fast so that you can recompute it on the various elements without worrying too much about performance.
When all those assumptions are met you can have a map object that "works like range
".
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…