十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
惰性求值,也就是延迟求值,表达式不会在它被绑定到变量之后就立即求值,而是等用到时再求值。这个特性可以解决一些巨大甚至无限的集合列表,如菲波那切数列、几十G的文件等等。延迟求值的一个好处是能够建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。
创新互联建站坚持“要么做到,要么别承诺”的工作理念,服务领域包括:成都网站制作、成都做网站、企业官网、英文网站、手机端网站、网站推广等服务,满足客户于互联网时代的福贡网站设计、移动媒体设计的需求,帮助企业找到有效的互联网解决方案。努力成为您成熟可靠的网络建设合作伙伴!
Python 中的很多方法没有直接返回列表,而是返回了一个可迭代的generator
(生成器)对象,这便是python的惰性求值,因为在创建一个很大的列表时,对内存的开销非常大,太大时python会直接报错,举个:chestnut::range()方法是产生一个指定范围列表,在Python3之前,该方法直接产生一个列表,xrange() 产生一个生成器:
xrange(100)
xrange(100)
range(100)
[0, 1, 2, 3,
4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89,
90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
当参数里面的值足够大时,range()产生了一个巨大的列表,这是内存会吃不消,等待一段时间后程序会直接被Kill掉:
for i in range(999999999999):
...
print i
...
Killed:
9
占满内存
用xrange() 方法就不回出现这种问题,并且可以一直运行:
for i in xrange(999999999999):
...
print i
...
1
2
3
4
5
6
7
8
9
10...
在Python3中range已经被改为了xrange,所以在python3中可以放心使用range().
惰性求值不要求你事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁
还有前文所说的list comprehension语句,在两边放上[],会产生别表,如果数据源很长则会报内存错误:
print [i for i in range(9999999999999999)]
Python(1627,0x7fffe5b713c0)
malloc: *** mach_vm_map(size=80000000000000000) failed
(error code=3)
*** error:
can't allocate region
*** set a
breakpoint in malloc_error_break to debug
Traceback
(most recent call last):
File "",
line 1, in /spanmodule
MemoryError
这样直接产生列表没有效率,为了创建生成器对象,可以在list
comprehension两边放上(),这样它就有了惰性求值的特性。
print((i for i
in range(99999999999999)))
使用next()内建函数访问生成器里的元素:
num =
(i for i in range(5))
num
next(num)
next(num)
1
for j in range(4):
...
print(next(num))
...
2
3
4
Traceback
(most recent call last):
File "",
line 2, in /spanmodule
StopIteration
当访问到最后元素时,再调用next(),Python将会抛出StopIteration异常。Python正是根据是否检查到这个异常来决定是否停止迭代。
step1 =
someLongOperation1()step2 = someLongOperation2()step3 =
concatenate(step1, step2)
以上代码需要分别执行一二两步操作,第三步用到一二两步的结果,在Pyhton中会有序的执行这些函数:首先是 someLongOperation1,然后 someLongOperation2,最后 concatenate,如果确保没有函数修改或依赖于全局变量,第一二步可以被并行执行。假设我们不想并行运行这两个函数,我们只在其他函数依赖于 step1 和 step2 时才需要执行这两个函数。我们甚至在concatenate 调用之前都不必执行他们,可以把他们的求值延迟到 concatenate 函数内实际用到他们的位置。如果函数中用到了if分支语句,条件无关step1和step2则可以尽量将判断条件放前面以减少不必要的计算:
step1 =
someLongOperation1()
step2 =
someLongOperation2()if condition:
step3 =
concatenate(step1, step2)
换为:if condition:
step1 =
someLongOperation1()
step2 =
someLongOperation2()
step3 =
concatenate(step1, step2)
如果 concatenate 是一个带有条件分支的函数并且有的分支中只用了两个参数中的一个,另一个参数就永远没有必要被求值。
lambda或者高阶函数是一种设计模式,是否适合应该要看更大范围的设计需要。
脱离了需求场景,返回lambda根本是脱裤子放屁。
map在python2返回list,在python3返回iterator.
如果想在python3得到可以反复重用的list,只要把iterator转成list即可:
lst_result = list(map(func, items))
Copyright © 1999-2020, CSDN.NET, All Rights Reserved
惰性计算的序列
打开APP
Python 的惰性求值与惰性序列 翻译
2018-07-23 14:57:48
2点赞
东师小镇
码龄5年
关注
惰性求值
在编程语言理论中,惰性求值(英语:Lazy Evaluation),又译为惰性计算、懒惰求值,也称为传需求调用(call-by-need),是一个计算机编程中的一个概念,它的目的是要最小化计算机要做的工作。它有两个相关而又有区别的含意,可以表示为“延迟求值”和“最小化求值”。
避免不必要的计算,带来性能的提升(最小化求值)。
对于Python中的条件表达式 if x and y,在x为false的情况下y表达式的值将不再计算。而对于if x or y,当x的值为true的时候将直接返回,不再计算y的值。因此编程中可以利用该特性,在 and逻辑中,将小概率发生的条件放在前面或者在or逻辑中,将大概率发生的时间放在前面,有助于性能的提升。
2. 节省空间,使得无线循环的数据结构成为可能(延迟求值)。
延迟求值特别用于函数式编程语言中。在使用延迟求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用的时候求值。延迟求值的一个好处是能够建立可计算的无限列表而没有妨碍计算的无限循环或大小问题。例如,可以建立生成无限斐波那契数列表的函数(经常叫做“流”)。第n个斐波那契数的计算仅是从这个无限列表上提取出这个元素,它只要求计算这个列表的前n个成员。
惰性序列
Python的惰性序列多数指 iterator,其特点正如同上文所述,具有惰性计算特点的序列称为惰性序列。
Python的iterator是一个惰性序列,意思是表达式和变量绑定后不会立即进行求值,而是当你用到其中某些元素的时候才去求某元素对的值。 惰性是指,你不主动去遍历它,就不会计算其中元素的值。
一句话理解:
迭代器的一个优点就是它不要求你事先准备好整个迭代过程中所有的元素。
迭代器仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。
这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。