当前位置: 首页 > 面试题库 >

懒惰评估地图

尤钱明
2023-03-14
问题内容

我最近读到map了Python 3的一个好处是它很懒。那就更好了

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惰性是重要的呢?


问题答案:

您在这里比较苹果和桔子。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急切的话iterablehtml" target="_blank">执行循环将消耗两倍的内存,而懒惰map的话,所需的唯一空间x基本上是。

此外,它可以调用map无限iterables
一样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.

但是,即使在这种情况下,您仍然会遇到一些问题:

  1. 如果sequence实际上是iterable,则要获取第n个元素,则必须消耗前n个元素。之后,您必须将它们作为序列存储在类中,以备将来使用。但这已经违反了整件事的目的,因为这样做PureMap(f, sequence)[1000]需要您始终将1000元素存储在内存中, 即使它避免了对的999调用f

  2. 您要避免f在同一元素上多次调用。这意味着您还必须跟踪已计算出哪个元素,而未计算出哪个元素。

可以实现所需目标的唯一情况如下:

  • 被调用的函数是纯函数
  • 可迭代的参数类似于这样range,它允许随机访问而不必产生其他元素
  • 您调用的函数很快,因此您可以在各种元素上重新计算它,而不必过多担心性能。

当所有这些假设都满足时,您可以拥有一个“像range”一样工作的地图对象。



 类似资料:
  • 问题内容: 例如,如果我有以下语句: 如果foo1为true,python将检查foo2的条件吗? 问题答案: 是的,Python懒惰地评估布尔条件。 该文件说, 表达式x和y首先计算x;如果x为假,则返回其值;否则,将评估y并返回结果值。 表达式x或y首先计算x; 如果x为true,则返回其值;否则,将评估y并返回结果值。

  • 我正在阅读HadleyWickhams关于Github的书,特别是关于懒惰评估的这一部分。在那里,他给出了一个懒惰求值结果的例子,在函数的添加部分。让我引用这一点: 这个[惰性评估]在使用lApplication或循环创建闭包时很重要: x在您第一次调用其中一个加法器函数时被延迟计算。此时,循环完成,x的最终值为10。因此,所有加法器函数都会在其输入中添加10,可能不是您想要的!手动强制评估解决了

  • 问题内容: 我在python应用程序中使用标准的python日志记录模块: 问题是,尽管未启用调试级别,但在每次循环迭代时都会评估该愚蠢的日志消息,这会严重损害性能。 有什么解决办法吗? 在C ++中,我们提供了提供以下宏的软件包: 有效评估为 但是,由于Python(AFAIK)中没有宏,是否有一种有效的日志记录方法? 问题答案: 日志记录模块已经对您要执行的操作提供了部分支持。做这个: …代替

  • 我已经写了两个版本的nqueens问题,我认为它们应该有相似的效率,但事实并非如此。我认为这是由于哈斯克尔的懒惰评估行为。有人能解释一下下面的例子是如何工作的吗, 您可以通过调用nqueens1 8 8或nqueens2 8 8对其进行评估,以对大小为8的板进行评估。 虽然nqueens2工作效率很高,但nqueens1存在性能问题。我相信这是因为递归调用(nqueens n(k-1))被多次评估

  • 问题内容: 什么是Python中的惰性评估? 一个网站说: 在Python 3.x中,该函数返回一个特殊的范围对象,该对象按需计算列表元素(延迟或延迟评估): 这是什么意思? 问题答案: 由(或在Python2.x中)返回的对象被称为惰性迭代。 生成器没有将整个范围存储在内存中,而是存储的定义并仅在需要时才计算下一个值(又称惰性求值)。 本质上,生成器允许您返回类似于结构的列表,但是这里有一些区别

  • 问题内容: 抱歉,这听起来像是一个很愚蠢的问题。 但是我在网上搜索了Google,还专门搜索了php.net网站和stackoverflow.com网站。 我知道PHP 在使用运算符时会进行 短路惰性评估 ,但是在PHP手册中它在何处清晰明了? 我发现只有Wikipedia作为唯一的“可信赖”资源,它说PHP对这些运算符进行了惰性评估。 问题答案: 我可以找到关于PHP的短路实现的“官方”最接近的