美文网首页
Python中的惰性计算

Python中的惰性计算

作者: MontyOak | 来源:发表于2017-03-05 11:00 被阅读645次

本文中所有代码均运行在Python 2.7上

从迭代器说起

迭代器(Iterator),顾名思义,就是一个可供迭代(Iterables)的对象。
比如,在一个列表中,依次读取其中的元素,就是一个迭代的过程。简单来说,可以使用for ... in ...语句迭代访问的对象,都是迭代器。其中包括list, set, string, dict , file等等。
这种简洁的迭代方式非常简便易用,但同时也带来了一个问题,因为迭代器中所有的数据都被放在内存中以供使用,所以会对内存造成很大的压力。
举个栗子:

>>> for num in range(10**1000):
           string = ' ' + ' '
....
OverflowError: range() result has too many items

也许在大多数场景中,我们不会去主动使用range()进行如此大的一个迭代,但我们很有可能会通过open()去打开一个大文件(可能是一个比较大的原始数据文件,或者一个大的log文件等),它的大小很有可能会大于运行环境的内存,这时候程序就会因为OverflowError而崩溃退出。

试试生成器?

同样的,生成器具备迭代器的所有特性,但是它仅供迭代一次,因为它采用的惰性计算的优化策略,就是说它只有当被使用到的时候才把数据取出或者计算出,放到内存中,访问之后随机销毁。
在使用上,它和迭代器的主要区别在于仅能进行一次迭代访问。

>>> iterator = [x for x in range(7)]
>>> Iterator
[0, 1, 2, 3, 4, 5, 6]
>>> generator = (x for x in range(7))
( generator object (genexpr) at 0X00000000025DBA20)

总结

在多数情况下,我们操作的数据量都不足以撼动内存,那是否意味着迭代对我们已经完全够用,生成器完全无用呢?
非也,惰性求值不仅在内存层级对空间有着优化的效果,在计算时间上也有着一定的提高。由于避免了不必要的计算,节省了计算资源。
最后以一个迭代器和生成器之间的斐波那契函数对比结束。

#先来一个迭代版本
def fib(n):
    a, b = 0, 1
    if n<2:
        return [a, b][n]
    for i in range():
        a, b = b, a+b
    return b
#之后是生成器版本
def fibHelper():
    a, b = 0, 1
    while True:
        yield a
        a, b = b, a+b
def fib(n):
    while n>0:
        result = fibHelper()
        n -= 1
    return result

相关文章

网友评论

      本文标题:Python中的惰性计算

      本文链接:https://www.haomeiwen.com/subject/onysgttx.html