我最近读到,Python 3中map
的一个好处是它很懒。这意味着,最好做
map(lambda x: x**2, range(10**100))
而不是
[x**2 for x in range(10**100)]
我很好奇,我是如何使用这种懒惰的。如果我生成地图对象,我怎么能访问结果操作/列表中的特定元素。在map
我见过的几乎所有文档中,他们都会做print(map(...))
或for i in map(...)
这样的事情(据我所知)放弃懒惰的概念,因为它隐含地转换了地图到列表。
我想我正在寻找的是能够以类似于range
的方式使用地图对象,我可以x = range(10**100)
并且懒惰地生成x[10000]
计算负荷。
如果这个概念不存在,那么让map
变得懒惰有什么好处?如果你总是需要将它转换为某个非惰性对象(如列表),为什么map
是懒惰的呢?
答案 0 :(得分:6)
您在这里将苹果与橙子进行比较。 range
不只是一个懒惰的可迭代。它是一个特定的对象,其内容满足特定的法则,允许支持许多操作而不实际在内存中构建一个巨大的序列。这是因为range
的第n个元素基本上只是start + n*step
(模stop
,符号等。)
但map
意味着与任何函数f
一起使用。特别是函数可能具有共享/全局状态,这已经失去了在不执行100个函数调用的情况下能够执行map(f, something)[100]
的任何机会。不这样做会破坏结果的正确性。
map
只是意味着它不会立即构建完整的结果列表,而是等待您在调用f
之前需要下一个结果并生成它。这样可以避免在以下代码中构建不必要的列表:
for x in map(f, iterable):
# do something with x
如果map
渴望它会消耗两倍iterable
的内存来进行循环,而懒惰map
所需的唯一空间基本上是x
的{{1}}
此外,它允许在无限迭代上调用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
一样工作”的地图对象。
答案 1 :(得分:1)
首先,请注意range
(Python 2中的xrange
)是一种特殊情况。它不是一个简单的生成器,也不会返回一个列表。它也支持in
操作,这不是迭代或迭代器的标准功能。
考虑可以在无限可迭代或可迭代上调用map(func, iterable)
,其中获取下一个值的过程是一个耗时的过程。
您需要知道您的函数可能会处理这些类型的值,并确保使用惰性函数,如itertools.imap
。由于基本上不可能确定迭代器是无限的,即使在运行时,内置函数也不应该对最广泛的输入正常运行吗?
并非每个用例都需要随机访问,而那些必须完全实例化iterable或使用itertools
之类的其他islice
函数。
答案 2 :(得分:1)
有很多好处;例如,它可以更容易地编写内存有效的代码。
def take_up_a_lot_of_memory(*args):
"""
A contrived example of a function that uses a lot of memory
"""
return sum([i ** 2 for i in range(10 ** 6)])
megasum = sum(map(take_up_a_lot_of_memory, range(1000)))
此外,有时您可以提前终止计算而不会遍历所有地图结果,从而避免冗余。