【问题标题】:python map, list(map), lambda and performancepython map、list(map)、lambda和性能
【发布时间】:2018-02-26 22:05:28
【问题描述】:

我做程序程序员已经有一段时间了,只是想改变我的思维方式来使用函数式编程(目前在 Python 3 中)。 因此,我没有编写 for-each 循环,而是试图掌握 maplist(map(..)) 之间的交互

假设我有一个简单的 for-in 循环,它执行一些资源繁重的计算(为了简单起见,我将在此处替换为 print):

arr = [1,2,3,4]    
for x in arr:
    print(x)

现在,当我尝试执行以下操作时

map(lambda x: print(x), arr)

什么都没有发生,直到,我将它包装在一个列表中,它完成了我的超重 print 功能:

list(map(lambda x: print(x), arr))

为什么?我错过了什么?我知道 map 返回一个迭代器,它应该可以节省内存,而不是立即保存整个列表。但是我的超重print函数什么时候才能触发呢?

【问题讨论】:

  • 好的,我理解这些概念,它们对我来说并不陌生。我的问题是,为什么当我不应用 list 包装器时该功能不起作用?因为我必须通过迭代器来触发它?
  • 是的@OgnjenMišić。 map 就是大家常说的懒惰。它不会做任何工作(即调用你的函数来计算任何值),除非它必须。您可以使用 next 强制 map 计算单个值。但是,当您将 map 迭代器转换为 list 时,您强制 map 计算其所有值并因此调用您的函数。
  • 因为它不会返回值列表。它返回迭代器本身。然后你在它上面调用next(some_iterator) 来消费下一个值,一个接一个。直到所有值都被消耗完。对它应用list 将使它适用于所有值并返回一个包含所有迭代器值的列表。或者你可以使用 for 循环
  • 好的,试了一下,谢谢大家,现在清楚多了。 @ChristianDean 发布您的回复,以便我接受 :)
  • 坦率地说,我原以为它可以像 JS 版本的地图一样工作,但现在又说得通了。

标签: python lambda functional-programming


【解决方案1】:

为什么?我错过了什么?我知道 map 返回一个迭代器,它应该可以节省内存,而不是立即保存整个列表。但是我的超重print函数什么时候才能触发呢?

map 函数在程序员术语中通常称为 lazy。它不会做任何工作,除非它必须。这在函数式编程中被更广泛地称为 lazy evaluationmap 函数不是立即计算任何值,而是返回所谓的 iterator。通过这样做,它会将计算它的值的工作委派给您返回给您

迭代器可以使用next计算单个值:

>>> arr = [1, 2, 3]
>>> it = map(lambda x: print(x), arr)
>>> next(it)
1
>>> 

但是,当您将 map 迭代器转换为列表时,您会强制 map 计算 其所有值,从而调用您的函数:

>>> it = map(lambda x: print(x), arr)
>>> list(it)
1
2
3
4
[None, None, None, None]
>>> 

【讨论】:

    【解决方案2】:

    正如您所说,您必须转换思维方式才能使用函数式编程。函数式编程的关键概念之一是lazy evaluation,这是Haskell 等语言中的默认策略。

    此策略的目的是通过仅在需要时计算某些内容来节省时间和内存。从这个意义上说,Python generators 也接近于函数式范式。

    如果你想尽快执行它,你不应该把它写成函数式的,如果你不关心结果,你不应该用list()修复它。使用循环是完全可以的。

    【讨论】:

    • 路易斯的回答很好!这很好地总结了map 和惰性评估背后的想法和目的。 +1
    • 感谢您的回复。我知道使用循环很好,但是什么时候写功能性的,什么时候写程序性的呢?假设我有一些嵌套的 for 循环,是否可以将它们内联到 list 包装器并一个接一个地执行一个 list-map-lambda 或仍然坚持嵌套?
    • 这真的取决于@OgnjenMišić。两种有效的编程范式各有利弊。在您的具体示例中,我会选择使用嵌套的 for 循环而不是嵌套的 map 调用,因为它通常会更快。另请查看comprehensions 并查看问题"OOP vs Functional Programming vs Procedural "
    • @OgnjenMišić 通常,列表理解比map + lambdafilter + filter + lambda,注意,当你想要同时映射 过滤器。但是在 Python 中,你应该只在可读的情况下使用这些结构,并且不要在它们内部使用副作用(...比如print...)
    猜你喜欢
    • 2020-06-26
    • 1970-01-01
    • 2018-06-27
    • 1970-01-01
    • 2017-03-21
    • 1970-01-01
    • 1970-01-01
    • 2020-01-26
    • 1970-01-01
    相关资源
    最近更新 更多