Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/285.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 地图的惰性评价_Python_Lazy Evaluation_Map Function - Fatal编程技术网

Python 地图的惰性评价

Python 地图的惰性评价,python,lazy-evaluation,map-function,Python,Lazy Evaluation,Map Function,我最近读到Python3中的map的一个好处是它很懒惰。也就是说,这样做更好 map(lambda x: x**2, range(10**100)) 而不是 [x**2 for x in range(10**100)] 我好奇的是,我如何利用这种懒惰。例如,如果生成映射对象,如何访问结果操作/列表中的特定元素。在我所看到的几乎所有关于map的文档中,他们都会为map中的I(…)或执行类似于print(map(…)的操作,据我所知,这会放弃惰性概念,因为它会隐式地将map转换为列表 我想我正在

我最近读到Python3中的
map
的一个好处是它很懒惰。也就是说,这样做更好

map(lambda x: x**2, range(10**100))
而不是

[x**2 for x in range(10**100)]
我好奇的是,我如何利用这种懒惰。例如,如果生成映射对象,如何访问结果操作/列表中的特定元素。在我所看到的几乎所有关于
map
的文档中,他们都会为map中的I(…)或
执行类似于
print(map(…)
的操作,据我所知,这会放弃惰性概念,因为它会隐式地将map转换为列表

我想我正在寻找的是以类似于
range
的惰性方式使用映射对象的能力,在这里我可以做
x=range(10**100)
并在没有巨大计算负载的情况下惰性地生成
x[10000]


如果这个概念不存在,那么让
map
懒惰有什么好处?如果您总是需要将其转换为一些非惰性对象(如列表),那么
map
是惰性的又有什么关系呢?

首先,请注意
range
xrange
在Python 2中)是一个特例。它不是一个简单的生成器,也不只是返回一个列表。它还支持
操作中的
,这不是iterables或迭代器的标准功能

假设
map(func,iterable)
可以在无限iterable上调用,或者在iterable上获取下一个值的过程非常耗时

您需要知道您的函数可能会处理这些类型的值,并确保使用惰性函数,如
itertools.imap
。既然基本上不可能确定迭代器是无限的,即使在运行时也是如此,那么内置函数是否应该在最广泛的输入范围内正确运行呢


并非每个用例都需要随机访问,那些需要随机访问的用例必须完全实例化iterable或使用另一个
itertools
函数,如
islice
,有很多好处;例如,它使编写内存效率高的代码变得更容易

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

此外,有时您可以提前终止计算,而无需遍历所有映射结果,从而避免冗余。

您在这里比较的是苹果和桔子<代码>范围
不是只是一个懒惰的变量。它是一个特定的对象,其内容满足特定的规则,允许支持许多操作,而无需在内存中实际构建庞大的序列。这是因为
范围
的第n个元素基本上就是
开始+n*步
(模
停止
,符号等)

然而,
map
意味着可以使用任何函数
f
。特别是,函数可能具有共享/全局状态,这已经使得不执行100个函数调用就无法执行
map(f,something)[100]
。不这样做会破坏结果的正确性

map
是惰性的,这意味着它不会立即构建一个完整的结果列表,而是在调用
f
并生成它之前,等待您需要下一个结果。这样可以避免在代码中生成不必要的列表,如:

for x in map(f, iterable):
    # do something with x
如果
map
是渴望的,则执行循环将消耗
iterable
的两倍内存,而使用惰性
map
时,所需的唯一空间基本上是
x
的空间

此外,它还允许对无限多个iterable(如
count()
)调用
map
。这显然会导致一个永无止境的程序做一些事情,或者在某个时候,您可以停止查看
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
    。这意味着您还必须跟踪哪个元素已经计算过,哪个元素没有计算过

  • 只有在以下情况下,您才能实现自己的目标:

    • 被调用的函数是纯函数
    • iterable参数类似于
      range
      ,它允许随机访问,而无需生成其他元素
    • 您调用的函数速度很快,因此您可以在各种元素上重新计算它,而不用太担心性能

    当所有这些假设都满足时,您可以拥有一个“工作方式类似于
    range

    的map对象。如果您需要第10000个元素,您可能需要计算前面的99999(除非您有一个简单的函数,如
    x**2
    ,在这种情况下只需执行
    10000**2
    ),您无法“索引到”它。懒惰是一个优势,因为你不需要一次在内存中保存整个列表。那么我的观点是,懒惰映射如何有用(而不是多余)?如果您关心内存,只需使用生成器。在您的示例中,迭代
    映射
    并不比迭代等效的生成器表达式好多少。两者都是懒散地评估的。与列表理解相比,它的优势在于不存储整个列表(这可能是不必要的,甚至是不可能的),这只是一个优势,如果您不需要同时存储所有列表。不清楚您想问什么:
    map
    vs列表<代码>地图<